Import release 0.1.9
[secnet] / netlink.c
CommitLineData
2fe58dfd
SE
1/* User-kernel network link */
2
baa06aeb
SE
3/* Each netlink device is actually a router, with its own IP address.
4 We do things like decreasing the TTL and recalculating the header
5 checksum, generating ICMP, responding to pings, etc. */
2fe58dfd
SE
6
7/* This is where we have the anti-spoofing paranoia - before sending a
8 packet to the kernel we check that the tunnel it came over could
9 reasonably have produced it. */
10
8689b3a9 11#include "secnet.h"
2fe58dfd 12#include "util.h"
7138d0c5 13#include "ipaddr.h"
9d3a4132 14#include "netlink.h"
042a8da9 15#include "process.h"
2fe58dfd 16
4efd681a
SE
17/* Generic IP checksum routine */
18static inline uint16_t ip_csum(uint8_t *iph,uint32_t count)
2fe58dfd 19{
4efd681a
SE
20 register uint32_t sum=0;
21
22 while (count>1) {
23 sum+=ntohs(*(uint16_t *)iph);
24 iph+=2;
25 count-=2;
26 }
27 if(count>0)
28 sum+=*(uint8_t *)iph;
29 while (sum>>16)
30 sum=(sum&0xffff)+(sum>>16);
31 return htons(~sum);
2fe58dfd
SE
32}
33
4efd681a
SE
34#ifdef i386
35/*
36 * This is a version of ip_compute_csum() optimized for IP headers,
37 * which always checksum on 4 octet boundaries.
38 *
39 * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
40 * Arnt Gulbrandsen.
41 */
42static inline uint16_t ip_fast_csum(uint8_t *iph, uint32_t ihl) {
43 uint32_t sum;
44
45 __asm__ __volatile__("
46 movl (%1), %0
47 subl $4, %2
48 jbe 2f
49 addl 4(%1), %0
50 adcl 8(%1), %0
51 adcl 12(%1), %0
521: adcl 16(%1), %0
53 lea 4(%1), %1
54 decl %2
55 jne 1b
56 adcl $0, %0
57 movl %0, %2
58 shrl $16, %0
59 addw %w2, %w0
60 adcl $0, %0
61 notl %0
622:
63 "
64 /* Since the input registers which are loaded with iph and ipl
65 are modified, we must also specify them as outputs, or gcc
66 will assume they contain their original values. */
67 : "=r" (sum), "=r" (iph), "=r" (ihl)
68 : "1" (iph), "2" (ihl));
69 return sum;
70}
71#else
72static inline uint16_t ip_fast_csum(uint8_t *iph, uint32_t ihl)
2fe58dfd 73{
4efd681a
SE
74 return ip_csum(iph,ihl*4);
75}
76#endif
77
78struct iphdr {
79#if defined (WORDS_BIGENDIAN)
80 uint8_t version:4,
81 ihl:4;
82#else
83 uint8_t ihl:4,
84 version:4;
85#endif
86 uint8_t tos;
87 uint16_t tot_len;
88 uint16_t id;
89 uint16_t frag_off;
90 uint8_t ttl;
91 uint8_t protocol;
92 uint16_t check;
93 uint32_t saddr;
94 uint32_t daddr;
95 /* The options start here. */
96};
97
98struct icmphdr {
99 struct iphdr iph;
100 uint8_t type;
101 uint8_t code;
102 uint16_t check;
103 union {
104 uint32_t unused;
105 struct {
106 uint8_t pointer;
107 uint8_t unused1;
108 uint16_t unused2;
109 } pprob;
110 uint32_t gwaddr;
111 struct {
112 uint16_t id;
113 uint16_t seq;
114 } echo;
115 } d;
116};
117
70dc107b
SE
118static void netlink_packet_deliver(struct netlink *st,
119 struct netlink_client *client,
120 struct buffer_if *buf);
4efd681a
SE
121
122static struct icmphdr *netlink_icmp_tmpl(struct netlink *st,
123 uint32_t dest,uint16_t len)
124{
125 struct icmphdr *h;
126
127 BUF_ALLOC(&st->icmp,"netlink_icmp_tmpl");
128 buffer_init(&st->icmp,st->max_start_pad);
129 h=buf_append(&st->icmp,sizeof(*h));
130
131 h->iph.version=4;
132 h->iph.ihl=5;
133 h->iph.tos=0;
134 h->iph.tot_len=htons(len+(h->iph.ihl*4)+8);
135 h->iph.id=0;
136 h->iph.frag_off=0;
137 h->iph.ttl=255;
138 h->iph.protocol=1;
139 h->iph.saddr=htonl(st->secnet_address);
140 h->iph.daddr=htonl(dest);
141 h->iph.check=0;
142 h->iph.check=ip_fast_csum((uint8_t *)&h->iph,h->iph.ihl);
143 h->check=0;
144 h->d.unused=0;
145
146 return h;
147}
148
149/* Fill in the ICMP checksum field correctly */
150static void netlink_icmp_csum(struct icmphdr *h)
151{
152 uint32_t len;
153
154 len=ntohs(h->iph.tot_len)-(4*h->iph.ihl);
155 h->check=0;
156 h->check=ip_csum(&h->type,len);
157}
158
159/* RFC1122:
160 * An ICMP error message MUST NOT be sent as the result of
161 * receiving:
162 *
163 * * an ICMP error message, or
164 *
165 * * a datagram destined to an IP broadcast or IP multicast
166 * address, or
167 *
168 * * a datagram sent as a link-layer broadcast, or
169 *
170 * * a non-initial fragment, or
171 *
172 * * a datagram whose source address does not define a single
173 * host -- e.g., a zero address, a loopback address, a
174 * broadcast address, a multicast address, or a Class E
175 * address.
176 */
177static bool_t netlink_icmp_may_reply(struct buffer_if *buf)
178{
179 struct iphdr *iph;
8dea8d37 180 struct icmphdr *icmph;
4efd681a
SE
181 uint32_t source;
182
183 iph=(struct iphdr *)buf->start;
8dea8d37
SE
184 icmph=(struct icmphdr *)buf->start;
185 if (iph->protocol==1) {
186 switch(icmph->type) {
187 case 3: /* Destination unreachable */
188 case 11: /* Time Exceeded */
189 case 12: /* Parameter Problem */
190 return False;
191 }
192 }
4efd681a
SE
193 /* How do we spot broadcast destination addresses? */
194 if (ntohs(iph->frag_off)&0x1fff) return False; /* Non-initial fragment */
195 source=ntohl(iph->saddr);
196 if (source==0) return False;
197 if ((source&0xff000000)==0x7f000000) return False;
198 /* How do we spot broadcast source addresses? */
199 if ((source&0xf0000000)==0xe0000000) return False; /* Multicast */
200 if ((source&0xf0000000)==0xf0000000) return False; /* Class E */
201 return True;
202}
203
204/* How much of the original IP packet do we include in its ICMP
205 response? The header plus up to 64 bits. */
206static uint16_t netlink_icmp_reply_len(struct buffer_if *buf)
207{
208 struct iphdr *iph=(struct iphdr *)buf->start;
209 uint16_t hlen,plen;
210
211 hlen=iph->ihl*4;
212 /* We include the first 8 bytes of the packet data, provided they exist */
213 hlen+=8;
214 plen=ntohs(iph->tot_len);
215 return (hlen>plen?plen:hlen);
216}
217
70dc107b
SE
218/* client indicates where the packet we're constructing a response to
219 comes from. NULL indicates the host. */
4efd681a 220static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf,
70dc107b 221 struct netlink_client *client,
4efd681a
SE
222 uint8_t type, uint8_t code)
223{
224 struct iphdr *iph=(struct iphdr *)buf->start;
225 struct icmphdr *h;
226 uint16_t len;
227
228 if (netlink_icmp_may_reply(buf)) {
229 len=netlink_icmp_reply_len(buf);
230 h=netlink_icmp_tmpl(st,ntohl(iph->saddr),len);
231 h->type=type; h->code=code;
232 memcpy(buf_append(&st->icmp,len),buf->start,len);
233 netlink_icmp_csum(h);
70dc107b 234 netlink_packet_deliver(st,NULL,&st->icmp);
4efd681a
SE
235 BUF_ASSERT_FREE(&st->icmp);
236 }
237}
238
239/*
240 * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the
241 * checksum.
242 *
243 * Is the datagram acceptable?
244 *
245 * 1. Length at least the size of an ip header
246 * 2. Version of 4
247 * 3. Checksums correctly.
248 * 4. Doesn't have a bogus length
249 */
250static bool_t netlink_check(struct netlink *st, struct buffer_if *buf)
251{
252 struct iphdr *iph=(struct iphdr *)buf->start;
253 uint32_t len;
254
9d3a4132
SE
255 if (iph->ihl < 5 || iph->version != 4) return False;
256 if (buf->size < iph->ihl*4) return False;
257 if (ip_fast_csum((uint8_t *)iph, iph->ihl)!=0) return False;
4efd681a
SE
258 len=ntohs(iph->tot_len);
259 /* There should be no padding */
9d3a4132 260 if (buf->size!=len || len<(iph->ihl<<2)) return False;
4efd681a
SE
261 /* XXX check that there's no source route specified */
262 return True;
263}
264
70dc107b
SE
265/* Deliver a packet. "client" points to the _origin_ of the packet, not
266 its destination. (May be used when sending ICMP response - avoid
267 asymmetric routing.) */
268static void netlink_packet_deliver(struct netlink *st,
269 struct netlink_client *client,
270 struct buffer_if *buf)
4efd681a
SE
271{
272 struct iphdr *iph=(struct iphdr *)buf->start;
273 uint32_t dest=ntohl(iph->daddr);
70dc107b
SE
274 uint32_t source=ntohl(iph->saddr);
275 uint32_t best_quality;
276 int best_match;
277 int i;
2fe58dfd 278
4efd681a 279 BUF_ASSERT_USED(buf);
2fe58dfd 280
4efd681a
SE
281 if (dest==st->secnet_address) {
282 Message(M_ERROR,"%s: trying to deliver a packet to myself!\n");
283 BUF_FREE(buf);
2fe58dfd
SE
284 return;
285 }
4efd681a 286
3454dce4
SE
287 /* XXX we're going to need an extra value 'allow_route' for the
288 source of the packet. It's always True for packets from the
289 host. For packets from tunnels, we consult the client
290 options. If !allow_route and the destination is a tunnel that
291 also doesn't allow routing, we must reject the packet with an
292 'administratively prohibited' or something similar ICMP. */
70dc107b
SE
293 if (!client) {
294 /* Origin of packet is host or secnet. Might be for a tunnel. */
295 best_quality=0;
296 best_match=-1;
297 for (i=0; i<st->n_routes; i++) {
9d3a4132 298 if (st->routes[i].up && subnet_match(&st->routes[i].net,dest)) {
70dc107b
SE
299 if (st->routes[i].c->link_quality>best_quality
300 || best_quality==0) {
301 best_quality=st->routes[i].c->link_quality;
302 best_match=i;
303 /* If quality isn't perfect we may wish to
304 consider kicking the tunnel with a 0-length
305 packet to prompt it to perform a key setup.
306 Then it'll eventually decide it's up or
307 down. */
308 /* If quality is perfect we don't need to search
309 any more. */
310 if (best_quality>=MAXIMUM_LINK_QUALITY) break;
311 }
312 }
313 }
314 if (best_match==-1) {
315 /* Not going down a tunnel. Might be for the host.
316 XXX think about this - only situation should be if we're
317 sending ICMP. */
318 if (source!=st->secnet_address) {
319 Message(M_ERROR,"netlink_packet_deliver: outgoing packet "
320 "from host that won't fit down any of our tunnels!\n");
9d3a4132
SE
321 /* XXX I think this could also occur if a soft tunnel just
322 went down, but still had packets queued in the kernel. */
70dc107b
SE
323 BUF_FREE(buf);
324 } else {
325 st->deliver_to_host(st->dst,NULL,buf);
326 BUF_ASSERT_FREE(buf);
327 }
328 } else {
329 if (best_quality>0) {
330 st->routes[best_match].c->deliver(
331 st->routes[best_match].c->dst,
332 st->routes[best_match].c, buf);
4efd681a
SE
333 BUF_ASSERT_FREE(buf);
334 } else {
335 /* Generate ICMP destination unreachable */
70dc107b 336 netlink_icmp_simple(st,buf,client,3,0); /* client==NULL */
4efd681a
SE
337 BUF_FREE(buf);
338 }
70dc107b
SE
339 }
340 } else { /* client is set */
341 /* We know the origin is a tunnel - packet must be for the host */
3454dce4
SE
342 /* XXX THIS IS NOT NECESSARILY TRUE, AND NEEDS FIXING */
343 /* THIS FUNCTION MUST JUST DELIVER THE PACKET: IT MUST ASSUME
344 THE PACKET HAS ALREADY BEEN CHECKED */
70dc107b
SE
345 if (subnet_matches_list(&st->networks,dest)) {
346 st->deliver_to_host(st->dst,NULL,buf);
347 BUF_ASSERT_FREE(buf);
348 } else {
349 Message(M_ERROR,"%s: packet from tunnel %s can't be delivered "
350 "to the host\n",st->name,client->name);
351 netlink_icmp_simple(st,buf,client,3,0);
352 BUF_FREE(buf);
2fe58dfd
SE
353 }
354 }
70dc107b 355 BUF_ASSERT_FREE(buf);
4efd681a
SE
356}
357
70dc107b
SE
358static void netlink_packet_forward(struct netlink *st,
359 struct netlink_client *client,
360 struct buffer_if *buf)
4efd681a
SE
361{
362 struct iphdr *iph=(struct iphdr *)buf->start;
363
364 BUF_ASSERT_USED(buf);
365
366 /* Packet has already been checked */
367 if (iph->ttl<=1) {
368 /* Generate ICMP time exceeded */
70dc107b 369 netlink_icmp_simple(st,buf,client,11,0);
4efd681a
SE
370 BUF_FREE(buf);
371 return;
372 }
373 iph->ttl--;
374 iph->check=0;
375 iph->check=ip_fast_csum((uint8_t *)iph,iph->ihl);
376
70dc107b 377 netlink_packet_deliver(st,client,buf);
4efd681a
SE
378 BUF_ASSERT_FREE(buf);
379}
380
9d3a4132 381/* Deal with packets addressed explicitly to us */
70dc107b
SE
382static void netlink_packet_local(struct netlink *st,
383 struct netlink_client *client,
384 struct buffer_if *buf)
4efd681a
SE
385{
386 struct icmphdr *h;
387
388 h=(struct icmphdr *)buf->start;
389
390 if ((ntohs(h->iph.frag_off)&0xbfff)!=0) {
9d3a4132
SE
391 Message(M_WARNING,"%s: fragmented packet addressed to secnet; "
392 "ignoring it\n",st->name);
4efd681a
SE
393 BUF_FREE(buf);
394 return;
395 }
396
397 if (h->iph.protocol==1) {
398 /* It's ICMP */
399 if (h->type==8 && h->code==0) {
400 /* ICMP echo-request. Special case: we re-use the buffer
401 to construct the reply. */
402 h->type=0;
403 h->iph.daddr=h->iph.saddr;
404 h->iph.saddr=htonl(st->secnet_address);
405 h->iph.ttl=255; /* Be nice and bump it up again... */
406 h->iph.check=0;
407 h->iph.check=ip_fast_csum((uint8_t *)h,h->iph.ihl);
408 netlink_icmp_csum(h);
70dc107b 409 netlink_packet_deliver(st,NULL,buf);
4efd681a
SE
410 return;
411 }
412 Message(M_WARNING,"%s: unknown incoming ICMP\n",st->name);
413 } else {
414 /* Send ICMP protocol unreachable */
70dc107b 415 netlink_icmp_simple(st,buf,client,3,2);
4efd681a
SE
416 BUF_FREE(buf);
417 return;
418 }
419
420 BUF_FREE(buf);
421}
422
9d3a4132
SE
423/* If cid==NULL packet is from host, otherwise cid specifies which tunnel
424 it came from. */
425static void netlink_incoming(void *sst, void *cid, struct buffer_if *buf)
4efd681a
SE
426{
427 struct netlink *st=sst;
9d3a4132 428 struct netlink_client *client=cid;
4efd681a
SE
429 uint32_t source,dest;
430 struct iphdr *iph;
431
432 BUF_ASSERT_USED(buf);
433 if (!netlink_check(st,buf)) {
9d3a4132
SE
434 Message(M_WARNING,"%s: bad IP packet from %s\n",
435 st->name,client?client->name:"host");
4efd681a
SE
436 BUF_FREE(buf);
437 return;
438 }
439 iph=(struct iphdr *)buf->start;
440
441 source=ntohl(iph->saddr);
442 dest=ntohl(iph->daddr);
443
9d3a4132
SE
444 /* Check source */
445 if (client) {
c6f79b17
SE
446 /* Check that the packet source is appropriate for the tunnel
447 it came down */
9d3a4132
SE
448 if (!subnet_matches_list(client->networks,source)) {
449 string_t s,d;
450 s=ipaddr_to_string(source);
451 d=ipaddr_to_string(dest);
452 Message(M_WARNING,"%s: packet from tunnel %s with bad "
453 "source address (s=%s,d=%s)\n",st->name,client->name,s,d);
454 free(s); free(d);
455 BUF_FREE(buf);
456 return;
457 }
458 } else {
c6f79b17
SE
459 /* Check that the packet originates in our configured local
460 network, and hasn't been forwarded from elsewhere or
461 generated with the wrong source address */
9d3a4132
SE
462 if (!subnet_matches_list(&st->networks,source)) {
463 string_t s,d;
464 s=ipaddr_to_string(source);
465 d=ipaddr_to_string(dest);
466 Message(M_WARNING,"%s: outgoing packet with bad source address "
467 "(s=%s,d=%s)\n",st->name,s,d);
468 free(s); free(d);
469 BUF_FREE(buf);
470 return;
471 }
4efd681a 472 }
c6f79b17
SE
473
474 /* If this is a point-to-point device we don't examine the packet at
475 all; we blindly send it down our one-and-only registered tunnel,
476 or to the host, depending on where it came from. */
477 if (st->ptp) {
478 if (client) {
479 st->deliver_to_host(st->dst,NULL,buf);
480 } else {
481 st->clients->deliver(st->clients->dst,NULL,buf);
482 }
483 BUF_ASSERT_FREE(buf);
484 return;
485 }
486
9d3a4132
SE
487 /* (st->secnet_address needs checking before matching destination
488 addresses) */
2fe58dfd 489 if (dest==st->secnet_address) {
9d3a4132 490 netlink_packet_local(st,client,buf);
4efd681a 491 BUF_ASSERT_FREE(buf);
2fe58dfd
SE
492 return;
493 }
9d3a4132 494 if (client) {
3454dce4 495 /* Check for free routing */
9d3a4132
SE
496 if (!subnet_matches_list(&st->networks,dest)) {
497 string_t s,d;
498 s=ipaddr_to_string(source);
499 d=ipaddr_to_string(dest);
500 Message(M_WARNING,"%s: incoming packet from tunnel %s "
501 "with bad destination address "
502 "(s=%s,d=%s)\n",st->name,client->name,s,d);
503 free(s); free(d);
504 BUF_FREE(buf);
505 return;
506 }
2fe58dfd 507 }
70dc107b 508 netlink_packet_forward(st,client,buf);
4efd681a
SE
509 BUF_ASSERT_FREE(buf);
510}
511
9d3a4132 512static void netlink_set_softlinks(struct netlink *st, struct netlink_client *c,
042a8da9 513 bool_t up, uint32_t quality)
4efd681a 514{
9d3a4132 515 uint32_t i;
4efd681a 516
9d3a4132
SE
517 if (!st->routes) return; /* Table has not yet been created */
518 for (i=0; i<st->n_routes; i++) {
042a8da9
SE
519 if (st->routes[i].c==c) {
520 st->routes[i].quality=quality;
521 if (!st->routes[i].hard) {
522 st->routes[i].up=up;
523 st->set_route(st->dst,&st->routes[i]);
524 }
9d3a4132 525 }
4efd681a 526 }
4efd681a
SE
527}
528
70dc107b 529static void netlink_set_quality(void *sst, void *cid, uint32_t quality)
4efd681a 530{
9d3a4132 531 struct netlink *st=sst;
4efd681a
SE
532 struct netlink_client *c=cid;
533
70dc107b 534 c->link_quality=quality;
9d3a4132 535 if (c->link_quality==LINK_QUALITY_DOWN) {
042a8da9 536 netlink_set_softlinks(st,c,False,c->link_quality);
9d3a4132 537 } else {
042a8da9 538 netlink_set_softlinks(st,c,True,c->link_quality);
9d3a4132 539 }
4efd681a
SE
540}
541
542static void *netlink_regnets(void *sst, struct subnet_list *nets,
543 netlink_deliver_fn *deliver, void *dst,
544 uint32_t max_start_pad, uint32_t max_end_pad,
3454dce4 545 uint32_t options, string_t client_name)
4efd681a
SE
546{
547 struct netlink *st=sst;
548 struct netlink_client *c;
549
550 Message(M_DEBUG_CONFIG,"netlink_regnets: request for %d networks, "
551 "max_start_pad=%d, max_end_pad=%d\n",
552 nets->entries,max_start_pad,max_end_pad);
553
3454dce4 554 if ((options&NETLINK_OPTION_SOFTROUTE) && !st->set_route) {
9d3a4132
SE
555 Message(M_ERROR,"%s: this netlink device does not support "
556 "soft routes.\n");
557 return NULL;
558 }
559
3454dce4 560 if (options&NETLINK_OPTION_SOFTROUTE) {
9d3a4132 561 /* XXX for now we assume that soft routes require root privilege;
3454dce4 562 this may not always be true. The device driver can tell us. */
9d3a4132
SE
563 require_root_privileges=True;
564 require_root_privileges_explanation="netlink: soft routes";
565 }
566
9d3a4132
SE
567 /* Check that nets do not intersect st->exclude_remote_networks;
568 refuse to register if they do. */
baa06aeb
SE
569 if (subnet_lists_intersect(&st->exclude_remote_networks,nets)) {
570 Message(M_ERROR,"%s: site %s specifies networks that "
571 "intersect with the explicitly excluded remote networks\n",
572 st->name,client_name);
c6f79b17
SE
573 return NULL;
574 }
575
576 if (st->clients && st->ptp) {
577 fatal("%s: only one site may use a point-to-point netlink device\n",
578 st->name);
579 return NULL;
baa06aeb
SE
580 }
581
4efd681a
SE
582 c=safe_malloc(sizeof(*c),"netlink_regnets");
583 c->networks=nets;
584 c->deliver=deliver;
585 c->dst=dst;
c6f79b17 586 c->name=client_name;
3454dce4 587 c->options=options;
70dc107b 588 c->link_quality=LINK_QUALITY_DOWN;
4efd681a
SE
589 c->next=st->clients;
590 st->clients=c;
591 if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
592 if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad;
70dc107b 593 st->n_routes+=nets->entries;
4efd681a
SE
594
595 return c;
596}
597
042a8da9 598static void netlink_dump_routes(struct netlink *st, bool_t requested)
9d3a4132
SE
599{
600 int i;
601 string_t net;
042a8da9 602 uint32_t c=M_INFO;
9d3a4132 603
042a8da9
SE
604 if (requested) c=M_WARNING;
605 Message(c,"%s: routing table:\n",st->name);
9d3a4132
SE
606 for (i=0; i<st->n_routes; i++) {
607 net=subnet_to_string(&st->routes[i].net);
042a8da9 608 Message(c,"%s -> tunnel %s (%s,%s route,%s,quality %d)\n",net,
3454dce4 609 st->routes[i].c->name,
9d3a4132 610 st->routes[i].hard?"hard":"soft",
3454dce4 611 st->routes[i].allow_route?"free":"restricted",
042a8da9
SE
612 st->routes[i].up?"up":"down",
613 st->routes[i].quality);
9d3a4132
SE
614 free(net);
615 }
042a8da9 616 Message(c,"%s/32 -> netlink \"%s\"\n",
9d3a4132
SE
617 ipaddr_to_string(st->secnet_address),st->name);
618 for (i=0; i<st->networks.entries; i++) {
619 net=subnet_to_string(&st->networks.list[i]);
042a8da9 620 Message(c,"%s -> host\n",net);
9d3a4132
SE
621 free(net);
622 }
623}
624
70dc107b
SE
625static int netlink_compare_route_specificity(const void *ap, const void *bp)
626{
627 const struct netlink_route *a=ap;
628 const struct netlink_route *b=bp;
629
630 if (a->net.len==b->net.len) return 0;
631 if (a->net.len<b->net.len) return 1;
632 return -1;
633}
634
635static void netlink_phase_hook(void *sst, uint32_t new_phase)
636{
637 struct netlink *st=sst;
638 struct netlink_client *c;
639 uint32_t i,j;
640
c6f79b17
SE
641 if (!st->clients && st->ptp) {
642 /* Point-to-point netlink devices must have precisely one
643 client. If none has registered by now, complain. */
644 fatal("%s: point-to-point netlink devices must have precisely "
645 "one client. This one doesn't have any.\n",st->name);
646 }
647
70dc107b
SE
648 /* All the networks serviced by the various tunnels should now
649 * have been registered. We build a routing table by sorting the
650 * routes into most-specific-first order. */
651 st->routes=safe_malloc(st->n_routes*sizeof(*st->routes),
652 "netlink_phase_hook");
653 /* Fill the table */
654 i=0;
655 for (c=st->clients; c; c=c->next) {
656 for (j=0; j<c->networks->entries; j++) {
657 st->routes[i].net=c->networks->list[j];
658 st->routes[i].c=c;
3454dce4
SE
659 /* Hard routes are always up;
660 soft routes default to down */
661 st->routes[i].up=c->options&NETLINK_OPTION_SOFTROUTE?False:True;
9d3a4132 662 st->routes[i].kup=False;
3454dce4
SE
663 st->routes[i].hard=c->options&NETLINK_OPTION_SOFTROUTE?False:True;
664 st->routes[i].allow_route=c->options&NETLINK_OPTION_ALLOW_ROUTE?
665 True:False;
042a8da9 666 st->routes[i].quality=c->link_quality;
70dc107b
SE
667 i++;
668 }
669 }
670 /* ASSERT i==st->n_routes */
671 if (i!=st->n_routes) {
672 fatal("netlink: route count error: expected %d got %d\n",
673 st->n_routes,i);
674 }
675 /* Sort the table in descending order of specificity */
676 qsort(st->routes,st->n_routes,sizeof(*st->routes),
677 netlink_compare_route_specificity);
9d3a4132 678
042a8da9
SE
679 netlink_dump_routes(st,False);
680}
681
682static void netlink_signal_handler(void *sst, int signum)
683{
684 struct netlink *st=sst;
685 Message(M_INFO,"%s: route dump requested by SIGUSR1\n",st->name);
686 netlink_dump_routes(st,True);
70dc107b
SE
687}
688
9d3a4132
SE
689netlink_deliver_fn *netlink_init(struct netlink *st,
690 void *dst, struct cloc loc,
691 dict_t *dict, string_t description,
692 netlink_route_fn *set_route,
693 netlink_deliver_fn *to_host)
4efd681a 694{
c6f79b17
SE
695 item_t *sa, *ptpa;
696
4efd681a
SE
697 st->dst=dst;
698 st->cl.description=description;
699 st->cl.type=CL_NETLINK;
700 st->cl.apply=NULL;
701 st->cl.interface=&st->ops;
702 st->ops.st=st;
703 st->ops.regnets=netlink_regnets;
9d3a4132 704 st->ops.deliver=netlink_incoming;
70dc107b 705 st->ops.set_quality=netlink_set_quality;
4efd681a
SE
706 st->max_start_pad=0;
707 st->max_end_pad=0;
708 st->clients=NULL;
9d3a4132 709 st->set_route=set_route;
4efd681a
SE
710 st->deliver_to_host=to_host;
711
712 st->name=dict_read_string(dict,"name",False,"netlink",loc);
713 if (!st->name) st->name=description;
714 dict_read_subnet_list(dict, "networks", True, "netlink", loc,
715 &st->networks);
baa06aeb
SE
716 dict_read_subnet_list(dict, "exclude-remote-networks", False, "netlink",
717 loc, &st->exclude_remote_networks);
b2a56f7c
SE
718 /* secnet-address does not have to be in local-networks;
719 however, it should be advertised in the 'sites' file for the
baa06aeb 720 local site. */
c6f79b17
SE
721 sa=dict_find_item(dict,"secnet-address",False,"netlink",loc);
722 ptpa=dict_find_item(dict,"ptp-address", False, "netlink", loc);
723 if (sa && ptpa) {
724 cfgfatal(loc,st->name,"you may not specify secnet-address and "
725 "ptp-address in the same netlink device\n");
726 }
727 if (!(sa || ptpa)) {
728 cfgfatal(loc,st->name,"you must specify secnet-address or "
729 "ptp-address for this netlink device\n");
730 }
731 if (sa) {
732 st->secnet_address=string_to_ipaddr(sa,"netlink");
733 st->ptp=False;
734 } else {
735 st->secnet_address=string_to_ipaddr(ptpa,"netlink");
736 st->ptp=True;
737 }
4efd681a
SE
738 st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
739 buffer_new(&st->icmp,ICMP_BUFSIZE);
70dc107b
SE
740 st->n_routes=0;
741 st->routes=NULL;
742
743 add_hook(PHASE_SETUP,netlink_phase_hook,st);
042a8da9 744 request_signal_notification(SIGUSR1, netlink_signal_handler, st);
4efd681a 745
9d3a4132 746 return netlink_incoming;
2fe58dfd
SE
747}
748
9d3a4132 749/* No connection to the kernel at all... */
2fe58dfd 750
9d3a4132 751struct null {
4efd681a 752 struct netlink nl;
4efd681a 753};
2fe58dfd 754
9d3a4132 755static bool_t null_set_route(void *sst, struct netlink_route *route)
4efd681a 756{
9d3a4132
SE
757 struct null *st=sst;
758 string_t t;
4efd681a 759
9d3a4132
SE
760 if (route->up!=route->kup) {
761 t=subnet_to_string(&route->net);
762 Message(M_INFO,"%s: setting route %s to state %s\n",st->nl.name,
763 t, route->up?"up":"down");
764 free(t);
765 route->kup=route->up;
766 return True;
2fe58dfd 767 }
9d3a4132 768 return False;
2fe58dfd 769}
9d3a4132 770
2fe58dfd
SE
771static void null_deliver(void *sst, void *cid, struct buffer_if *buf)
772{
773 return;
774}
775
776static list_t *null_apply(closure_t *self, struct cloc loc, dict_t *context,
777 list_t *args)
778{
779 struct null *st;
4efd681a
SE
780 item_t *item;
781 dict_t *dict;
2fe58dfd 782
4efd681a 783 st=safe_malloc(sizeof(*st),"null_apply");
2fe58dfd 784
4efd681a
SE
785 item=list_elem(args,0);
786 if (!item || item->type!=t_dict)
787 cfgfatal(loc,"null-netlink","parameter must be a dictionary\n");
788
789 dict=item->data.dict;
790
9d3a4132
SE
791 netlink_init(&st->nl,st,loc,dict,"null-netlink",null_set_route,
792 null_deliver);
4efd681a
SE
793
794 return new_closure(&st->nl.cl);
2fe58dfd
SE
795}
796
797init_module netlink_module;
798void netlink_module(dict_t *dict)
799{
4efd681a 800 add_closure(dict,"null-netlink",null_apply);
2fe58dfd 801}