Import release 0.1.9
[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 struct icmphdr *icmph;
181 uint32_t source;
182
183 iph=(struct iphdr *)buf->start;
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 }
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. */
206 static 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
218 /* client indicates where the packet we're constructing a response to
219 comes from. NULL indicates the host. */
220 static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf,
221 struct netlink_client *client,
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);
234 netlink_packet_deliver(st,NULL,&st->icmp);
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 */
250 static 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
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;
258 len=ntohs(iph->tot_len);
259 /* There should be no padding */
260 if (buf->size!=len || len<(iph->ihl<<2)) return False;
261 /* XXX check that there's no source route specified */
262 return True;
263 }
264
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.) */
268 static void netlink_packet_deliver(struct netlink *st,
269 struct netlink_client *client,
270 struct buffer_if *buf)
271 {
272 struct iphdr *iph=(struct iphdr *)buf->start;
273 uint32_t dest=ntohl(iph->daddr);
274 uint32_t source=ntohl(iph->saddr);
275 uint32_t best_quality;
276 int best_match;
277 int i;
278
279 BUF_ASSERT_USED(buf);
280
281 if (dest==st->secnet_address) {
282 Message(M_ERROR,"%s: trying to deliver a packet to myself!\n");
283 BUF_FREE(buf);
284 return;
285 }
286
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. */
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++) {
298 if (st->routes[i].up && subnet_match(&st->routes[i].net,dest)) {
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");
321 /* XXX I think this could also occur if a soft tunnel just
322 went down, but still had packets queued in the kernel. */
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);
333 BUF_ASSERT_FREE(buf);
334 } else {
335 /* Generate ICMP destination unreachable */
336 netlink_icmp_simple(st,buf,client,3,0); /* client==NULL */
337 BUF_FREE(buf);
338 }
339 }
340 } else { /* client is set */
341 /* We know the origin is a tunnel - packet must be for the host */
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 */
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);
353 }
354 }
355 BUF_ASSERT_FREE(buf);
356 }
357
358 static void netlink_packet_forward(struct netlink *st,
359 struct netlink_client *client,
360 struct buffer_if *buf)
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 */
369 netlink_icmp_simple(st,buf,client,11,0);
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
377 netlink_packet_deliver(st,client,buf);
378 BUF_ASSERT_FREE(buf);
379 }
380
381 /* Deal with packets addressed explicitly to us */
382 static void netlink_packet_local(struct netlink *st,
383 struct netlink_client *client,
384 struct buffer_if *buf)
385 {
386 struct icmphdr *h;
387
388 h=(struct icmphdr *)buf->start;
389
390 if ((ntohs(h->iph.frag_off)&0xbfff)!=0) {
391 Message(M_WARNING,"%s: fragmented packet addressed to secnet; "
392 "ignoring it\n",st->name);
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);
409 netlink_packet_deliver(st,NULL,buf);
410 return;
411 }
412 Message(M_WARNING,"%s: unknown incoming ICMP\n",st->name);
413 } else {
414 /* Send ICMP protocol unreachable */
415 netlink_icmp_simple(st,buf,client,3,2);
416 BUF_FREE(buf);
417 return;
418 }
419
420 BUF_FREE(buf);
421 }
422
423 /* If cid==NULL packet is from host, otherwise cid specifies which tunnel
424 it came from. */
425 static void netlink_incoming(void *sst, void *cid, struct buffer_if *buf)
426 {
427 struct netlink *st=sst;
428 struct netlink_client *client=cid;
429 uint32_t source,dest;
430 struct iphdr *iph;
431
432 BUF_ASSERT_USED(buf);
433 if (!netlink_check(st,buf)) {
434 Message(M_WARNING,"%s: bad IP packet from %s\n",
435 st->name,client?client->name:"host");
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
444 /* Check source */
445 if (client) {
446 /* Check that the packet source is appropriate for the tunnel
447 it came down */
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 {
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 */
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 }
472 }
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
487 /* (st->secnet_address needs checking before matching destination
488 addresses) */
489 if (dest==st->secnet_address) {
490 netlink_packet_local(st,client,buf);
491 BUF_ASSERT_FREE(buf);
492 return;
493 }
494 if (client) {
495 /* Check for free routing */
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 }
507 }
508 netlink_packet_forward(st,client,buf);
509 BUF_ASSERT_FREE(buf);
510 }
511
512 static void netlink_set_softlinks(struct netlink *st, struct netlink_client *c,
513 bool_t up, uint32_t quality)
514 {
515 uint32_t i;
516
517 if (!st->routes) return; /* Table has not yet been created */
518 for (i=0; i<st->n_routes; i++) {
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 }
525 }
526 }
527 }
528
529 static void netlink_set_quality(void *sst, void *cid, uint32_t quality)
530 {
531 struct netlink *st=sst;
532 struct netlink_client *c=cid;
533
534 c->link_quality=quality;
535 if (c->link_quality==LINK_QUALITY_DOWN) {
536 netlink_set_softlinks(st,c,False,c->link_quality);
537 } else {
538 netlink_set_softlinks(st,c,True,c->link_quality);
539 }
540 }
541
542 static 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,
545 uint32_t options, string_t client_name)
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
554 if ((options&NETLINK_OPTION_SOFTROUTE) && !st->set_route) {
555 Message(M_ERROR,"%s: this netlink device does not support "
556 "soft routes.\n");
557 return NULL;
558 }
559
560 if (options&NETLINK_OPTION_SOFTROUTE) {
561 /* XXX for now we assume that soft routes require root privilege;
562 this may not always be true. The device driver can tell us. */
563 require_root_privileges=True;
564 require_root_privileges_explanation="netlink: soft routes";
565 }
566
567 /* Check that nets do not intersect st->exclude_remote_networks;
568 refuse to register if they do. */
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);
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;
580 }
581
582 c=safe_malloc(sizeof(*c),"netlink_regnets");
583 c->networks=nets;
584 c->deliver=deliver;
585 c->dst=dst;
586 c->name=client_name;
587 c->options=options;
588 c->link_quality=LINK_QUALITY_DOWN;
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;
593 st->n_routes+=nets->entries;
594
595 return c;
596 }
597
598 static void netlink_dump_routes(struct netlink *st, bool_t requested)
599 {
600 int i;
601 string_t net;
602 uint32_t c=M_INFO;
603
604 if (requested) c=M_WARNING;
605 Message(c,"%s: routing table:\n",st->name);
606 for (i=0; i<st->n_routes; i++) {
607 net=subnet_to_string(&st->routes[i].net);
608 Message(c,"%s -> tunnel %s (%s,%s route,%s,quality %d)\n",net,
609 st->routes[i].c->name,
610 st->routes[i].hard?"hard":"soft",
611 st->routes[i].allow_route?"free":"restricted",
612 st->routes[i].up?"up":"down",
613 st->routes[i].quality);
614 free(net);
615 }
616 Message(c,"%s/32 -> netlink \"%s\"\n",
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]);
620 Message(c,"%s -> host\n",net);
621 free(net);
622 }
623 }
624
625 static 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
635 static 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
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
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;
659 /* Hard routes are always up;
660 soft routes default to down */
661 st->routes[i].up=c->options&NETLINK_OPTION_SOFTROUTE?False:True;
662 st->routes[i].kup=False;
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;
666 st->routes[i].quality=c->link_quality;
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);
678
679 netlink_dump_routes(st,False);
680 }
681
682 static 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);
687 }
688
689 netlink_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)
694 {
695 item_t *sa, *ptpa;
696
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;
704 st->ops.deliver=netlink_incoming;
705 st->ops.set_quality=netlink_set_quality;
706 st->max_start_pad=0;
707 st->max_end_pad=0;
708 st->clients=NULL;
709 st->set_route=set_route;
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);
716 dict_read_subnet_list(dict, "exclude-remote-networks", False, "netlink",
717 loc, &st->exclude_remote_networks);
718 /* secnet-address does not have to be in local-networks;
719 however, it should be advertised in the 'sites' file for the
720 local site. */
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 }
738 st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
739 buffer_new(&st->icmp,ICMP_BUFSIZE);
740 st->n_routes=0;
741 st->routes=NULL;
742
743 add_hook(PHASE_SETUP,netlink_phase_hook,st);
744 request_signal_notification(SIGUSR1, netlink_signal_handler, st);
745
746 return netlink_incoming;
747 }
748
749 /* No connection to the kernel at all... */
750
751 struct null {
752 struct netlink nl;
753 };
754
755 static bool_t null_set_route(void *sst, struct netlink_route *route)
756 {
757 struct null *st=sst;
758 string_t t;
759
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;
767 }
768 return False;
769 }
770
771 static void null_deliver(void *sst, void *cid, struct buffer_if *buf)
772 {
773 return;
774 }
775
776 static list_t *null_apply(closure_t *self, struct cloc loc, dict_t *context,
777 list_t *args)
778 {
779 struct null *st;
780 item_t *item;
781 dict_t *dict;
782
783 st=safe_malloc(sizeof(*st),"null_apply");
784
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
791 netlink_init(&st->nl,st,loc,dict,"null-netlink",null_set_route,
792 null_deliver);
793
794 return new_closure(&st->nl.cl);
795 }
796
797 init_module netlink_module;
798 void netlink_module(dict_t *dict)
799 {
800 add_closure(dict,"null-netlink",null_apply);
801 }