Fix compiler warnings on some BSD variants.
[tinc] / src / info.c
1 /*
2     info.c -- Show information about a node, subnet or address
3     Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "system.h"
21
22 #include "control_common.h"
23 #include "list.h"
24 #include "subnet.h"
25 #include "tincctl.h"
26 #include "info.h"
27 #include "xalloc.h"
28
29 void logger(int level, int priority, const char *format, ...) {
30         va_list ap;
31         va_start(ap, format);
32         vfprintf(stderr, format, ap);
33         va_end(ap);
34 }
35
36 char *strip_weight(char *netstr) {
37         int len = strlen(netstr);
38         if(len >= 3 && !strcmp(netstr + len - 3, "#10"))
39                 netstr[len - 3] = 0;
40         return netstr;
41 }
42
43 static int info_node(int fd, const char *item) {
44         // Check the list of nodes
45         sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_NODES, item);
46
47         bool found = false;
48         char line[4096];
49
50         char node[4096];
51         char from[4096];
52         char to[4096];
53         char subnet[4096];
54         char host[4096];
55         char port[4096];
56         char via[4096];
57         char nexthop[4096];
58         int code, req, cipher, digest, maclength, compression, distance;
59         short int pmtu, minmtu, maxmtu;
60         unsigned int options;
61         union {
62                 node_status_t bits;
63                 uint32_t raw;
64         } status_union;
65         node_status_t status;
66         long int last_state_change;
67
68         while(recvline(fd, line, sizeof line)) {
69                 int n = sscanf(line, "%d %d %s %s port %s %d %d %d %d %x %"PRIx32" %s %s %d %hd %hd %hd %ld", &code, &req, node, host, port, &cipher, &digest, &maclength, &compression, &options, &status_union.raw, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
70
71                 if(n == 2)
72                         break;
73
74                 if(n != 18) {
75                         fprintf(stderr, "Unable to parse node dump from tincd.\n");
76                         return 1;
77                 }
78
79                 if(!strcmp(node, item)) {
80                         found = true;
81                         break;
82                 }
83         }
84
85         if(!found) {
86                 fprintf(stderr, "Unknown node %s.\n", item);
87                 return 1;
88         }
89
90         while(recvline(fd, line, sizeof line)) {
91                 if(sscanf(line, "%d %d %s", &code, &req, node) == 2)
92                         break;
93         }
94
95         printf("Node:         %s\n", item);
96         printf("Address:      %s port %s\n", host, port);
97
98         char timestr[32] = "never";
99         time_t lsc_time = last_state_change;
100
101         if(last_state_change)
102                 strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&lsc_time));
103
104         status = status_union.bits;
105
106         if(status.reachable)
107                 printf("Online since: %s\n", timestr);
108         else
109                 printf("Last seen:    %s\n", timestr);
110
111         printf("Status:      ");
112         if(status.validkey)
113                 printf(" validkey");
114         if(status.visited)
115                 printf(" visited");
116         if(status.reachable)
117                 printf(" reachable");
118         if(status.indirect)
119                 printf(" indirect");
120         if(status.sptps)
121                 printf(" sptps");
122         if(status.udp_confirmed)
123                 printf(" udp_confirmed");
124         printf("\n");
125
126         printf("Options:     ");
127         if(options & OPTION_INDIRECT)
128                 printf(" indirect");
129         if(options & OPTION_TCPONLY)
130                 printf(" tcponly");
131         if(options & OPTION_PMTU_DISCOVERY)
132                 printf(" pmtu_discovery");
133         if(options & OPTION_CLAMP_MSS)
134                 printf(" clamp_mss");
135         printf("\n");
136         printf("Protocol:     %d.%d\n", PROT_MAJOR, OPTION_VERSION(options));
137         printf("Reachability: ");
138         if(!strcmp(host, "MYSELF"))
139                 printf("can reach itself\n");
140         else if(!status.reachable)
141                 printf("unreachable\n");
142         else if(strcmp(via, item))
143                 printf("indirectly via %s\n", via);
144         else if(!status.validkey)
145                 printf("unknown\n");
146         else if(minmtu > 0)
147                 printf("directly with UDP\nPMTU:         %d\n", pmtu);
148         else if(!strcmp(nexthop, item))
149                 printf("directly with TCP\n");
150         else
151                 printf("none, forwarded via %s\n", nexthop);
152
153         // List edges
154         printf("Edges:       ");
155         sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_EDGES, item);
156         while(recvline(fd, line, sizeof line)) {
157                 int n = sscanf(line, "%d %d %s %s", &code, &req, from, to);
158                 if(n == 2)
159                         break;
160                 if(n != 4) {
161                         fprintf(stderr, "Unable to parse edge dump from tincd.\n%s\n", line);
162                         return 1;
163                 }
164                 if(!strcmp(from, item))
165                         printf(" %s", to);
166         }
167         printf("\n");
168
169         // List subnets
170         printf("Subnets:     ");
171         sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_SUBNETS, item);
172         while(recvline(fd, line, sizeof line)) {
173                 int n = sscanf(line, "%d %d %s %s", &code, &req, subnet, from);
174                 if(n == 2)
175                         break;
176                 if(n != 4) {
177                         fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
178                         return 1;
179                 }
180                 if(!strcmp(from, item))
181                         printf(" %s", strip_weight(subnet));
182         }
183         printf("\n");
184
185         return 0;
186 }
187
188 static int info_subnet(int fd, const char *item) {
189         subnet_t subnet, find;
190
191         if(!str2net(&find, item)) {
192                 fprintf(stderr, "Could not parse subnet or address '%s'.\n", item);
193                 return 1;
194         }
195
196         bool address = !strchr(item, '/');
197         bool weight = strchr(item, '#');
198         bool found = false;
199
200         char line[4096];
201         char netstr[4096];
202         char owner[4096];
203
204         int code, req;
205
206         sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_SUBNETS, item);
207         while(recvline(fd, line, sizeof line)) {
208                 int n = sscanf(line, "%d %d %s %s", &code, &req, netstr, owner);
209                 if(n == 2)
210                         break;
211
212                 if(n != 4 || !str2net(&subnet, netstr)) {
213                         fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
214                         return 1;
215                 }
216
217                 if(find.type != subnet.type)
218                         continue;
219
220                 if(weight) {
221                         if(find.weight != subnet.weight)
222                                 continue;
223                 }
224
225                 if(find.type == SUBNET_IPV4) {
226                         if(address) {
227                                 if(maskcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, subnet.net.ipv4.prefixlength))
228                                         continue;
229                         } else {
230                                 if(find.net.ipv4.prefixlength != subnet.net.ipv4.prefixlength)
231                                         continue;
232                                 if(memcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, sizeof subnet.net.ipv4))
233                                         continue;
234                         }
235                 } else if(find.type == SUBNET_IPV6) {
236                         if(address) {
237                                 if(maskcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, subnet.net.ipv6.prefixlength))
238                                         continue;
239                         } else {
240                                 if(find.net.ipv6.prefixlength != subnet.net.ipv6.prefixlength)
241                                         continue;
242                                 if(memcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, sizeof subnet.net.ipv6))
243                                         continue;
244                         }
245                 } if(find.type == SUBNET_MAC) {
246                         if(memcmp(&find.net.mac.address, &subnet.net.mac.address, sizeof subnet.net.mac))
247                                 continue;
248                 }
249
250                 found = true;
251                 printf("Subnet: %s\n", strip_weight(netstr));
252                 printf("Owner:  %s\n", owner);
253         }
254
255         if(!found) {
256                 if(address)
257                         fprintf(stderr, "Unknown address %s.\n", item);
258                 else
259                         fprintf(stderr, "Unknown subnet %s.\n", item);
260                 return 1;
261         }
262
263         return 0;
264 }
265
266 int info(int fd, const char *item) {
267         if(check_id(item))
268                 return info_node(fd, item);
269         if(strchr(item, '.') || strchr(item, ':'))
270                 return info_subnet(fd, item);
271
272         fprintf(stderr, "Argument is not a node name, subnet or address.\n");
273         return 1;
274 }