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