Merge branch 'master' into 1.1
[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         node_status_t status;
62         long int last_state_change;
63
64         while(recvline(fd, line, sizeof line)) {
65                 int n = sscanf(line, "%d %d %s %s port %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", &code, &req, node, host, port, &cipher, &digest, &maclength, &compression, &options, (unsigned *)&status, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
66
67                 if(n == 2)
68                         break;
69
70                 if(n != 18) {
71                         fprintf(stderr, "Unable to parse node dump from tincd.\n");
72                         return 1;
73                 }
74
75                 if(!strcmp(node, item)) {
76                         found = true;
77                         break;
78                 }
79         }
80
81         if(!found) {
82                 fprintf(stderr, "Unknown node %s.\n", item);
83                 return 1;
84         }
85
86         while(recvline(fd, line, sizeof line)) {
87                 if(sscanf(line, "%d %d %s", &code, &req, node) == 2)
88                         break;
89         }
90         
91         printf("Node:         %s\n", item);
92         printf("Address:      %s port %s\n", host, port);
93
94         char timestr[32] = "never";
95         if(last_state_change)
96                 strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&last_state_change));
97
98         if(status.reachable)
99                 printf("Online since: %s\n", timestr);
100         else
101                 printf("Last seen:    %s\n", timestr);
102
103         printf("Status:      ");
104         if(status.validkey)
105                 printf(" validkey");
106         if(status.visited)
107                 printf(" visited");
108         if(status.reachable)
109                 printf(" reachable");
110         if(status.indirect)
111                 printf(" indirect");
112         if(status.sptps)
113                 printf(" sptps");
114         printf("\n");
115
116         printf("Options:     ");
117         if(options & OPTION_INDIRECT)
118                 printf(" indirect");
119         if(options & OPTION_TCPONLY)
120                 printf(" tcponly");
121         if(options & OPTION_PMTU_DISCOVERY)
122                 printf(" pmtu_discovery");
123         if(options & OPTION_CLAMP_MSS)
124                 printf(" clamp_mss");
125         printf("\n");
126         printf("Protocol:     %d.%d\n", PROT_MAJOR, OPTION_VERSION(options));
127         printf("Reachability: ");
128         if(!strcmp(host, "MYSELF"))
129                 printf("can reach itself\n");
130         else if(!status.reachable)
131                 printf("unreachable\n");
132         else if(strcmp(via, item))
133                 printf("indirectly via %s\n", via);
134         else if(!status.validkey)
135                 printf("unknown\n");
136         else if(minmtu > 0)
137                 printf("directly with UDP\nPMTU:         %d\n", pmtu);
138         else if(!strcmp(nexthop, item))
139                 printf("directly with TCP\n");
140         else
141                 printf("none, forwarded via %s\n", nexthop);
142
143         // List edges
144         printf("Edges:       ");
145         sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_EDGES, item);
146         while(recvline(fd, line, sizeof line)) {
147                 int n = sscanf(line, "%d %d %s %s", &code, &req, from, to);
148                 if(n == 2)
149                         break;
150                 if(n != 4) {
151                         fprintf(stderr, "Unable to parse edge dump from tincd.\n%s\n", line);
152                         return 1;
153                 }
154                 if(!strcmp(from, item))
155                         printf(" %s", to);
156         }
157         printf("\n");
158
159         // List subnets
160         printf("Subnets:     ");
161         sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_SUBNETS, item);
162         while(recvline(fd, line, sizeof line)) {
163                 int n = sscanf(line, "%d %d %s %s", &code, &req, subnet, from);
164                 if(n == 2)
165                         break;
166                 if(n != 4) {
167                         fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
168                         return 1;
169                 }
170                 if(!strcmp(from, item))
171                         printf(" %s", strip_weight(subnet));
172         }
173         printf("\n");
174
175         return 0;
176 }
177
178 static int info_subnet(int fd, const char *item) {
179         subnet_t subnet, find;
180
181         if(!str2net(&find, item)) {
182                 fprintf(stderr, "Could not parse subnet or address '%s'.\n", item);
183                 return 1;
184         }
185
186         bool address = !strchr(item, '/');
187         bool weight = strchr(item, '#');
188         bool found = false;
189
190         char line[4096];
191         char netstr[4096];
192         char owner[4096];
193
194         int code, req;
195
196         sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_SUBNETS, item);
197         while(recvline(fd, line, sizeof line)) {
198                 int n = sscanf(line, "%d %d %s %s", &code, &req, netstr, owner);
199                 if(n == 2)
200                         break;
201
202                 if(n != 4 || !str2net(&subnet, netstr)) {
203                         fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
204                         return 1;
205                 }
206
207                 if(find.type != subnet.type)
208                         continue;
209
210                 if(weight) {
211                         if(find.weight != subnet.weight)
212                                 continue;
213                 }
214
215                 if(find.type == SUBNET_IPV4) {
216                         if(address) {
217                                 if(maskcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, subnet.net.ipv4.prefixlength))
218                                         continue;
219                         } else {
220                                 if(find.net.ipv4.prefixlength != subnet.net.ipv4.prefixlength)
221                                         continue;
222                                 if(memcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, sizeof subnet.net.ipv4))
223                                         continue;
224                         }
225                 } else if(find.type == SUBNET_IPV6) {
226                         if(address) {
227                                 if(maskcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, subnet.net.ipv6.prefixlength))
228                                         continue;
229                         } else {
230                                 if(find.net.ipv6.prefixlength != subnet.net.ipv6.prefixlength)
231                                         continue;
232                                 if(memcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, sizeof subnet.net.ipv6))
233                                         continue;
234                         }
235                 } if(find.type == SUBNET_MAC) {
236                         if(memcmp(&find.net.mac.address, &subnet.net.mac.address, sizeof subnet.net.mac))
237                                 continue;
238                 }
239
240                 found = true;
241                 printf("Subnet: %s\n", strip_weight(netstr));
242                 printf("Owner:  %s\n", owner);
243         }
244
245         if(!found) {
246                 if(address)
247                         fprintf(stderr, "Unknown address %s.\n", item);
248                 else
249                         fprintf(stderr, "Unknown subnet %s.\n", item);
250                 return 1;
251         }
252
253         return 0;
254 }
255
256 int info(int fd, const char *item) {
257         if(check_id(item))
258                 return info_node(fd, item);
259         if(strchr(item, '.') || strchr(item, ':'))
260                 return info_subnet(fd, item);
261
262         fprintf(stderr, "Argument is not a node name, subnet or address.\n");
263         return 1;
264 }