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