chiark / gitweb /
e41445cb47c147929e6c3f6f84e7a6691fa03144
[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 (ipset_contains_addr(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     /* XXX consider generating ICMP if we're not point-to-point and we
470        don't like the packet */
471     if (client) {
472         /* Check that the packet source is appropriate for the tunnel
473            it came down */
474         if (!ipset_contains_addr(client->networks,source)) {
475             string_t s,d;
476             s=ipaddr_to_string(source);
477             d=ipaddr_to_string(dest);
478             Message(M_WARNING,"%s: packet from tunnel %s with bad "
479                     "source address (s=%s,d=%s)\n",st->name,client->name,s,d);
480             free(s); free(d);
481             BUF_FREE(buf);
482             return;
483         }
484     } else {
485         /* Check that the packet originates in our configured local
486            network, and hasn't been forwarded from elsewhere or
487            generated with the wrong source address */
488         if (!ipset_contains_addr(st->networks,source)) {
489             string_t s,d;
490             s=ipaddr_to_string(source);
491             d=ipaddr_to_string(dest);
492             Message(M_WARNING,"%s: outgoing packet with bad source address "
493                     "(s=%s,d=%s)\n",st->name,s,d);
494             free(s); free(d);
495             BUF_FREE(buf);
496             return;
497         }
498     }
499
500     /* If this is a point-to-point device we don't examine the
501        destination address at all; we blindly send it down our
502        one-and-only registered tunnel, or to the host, depending on
503        where it came from. */
504     /* XXX I think we should check destination addresses */
505     if (st->ptp) {
506         if (client) {
507             st->deliver_to_host(st->dst,buf);
508         } else {
509             st->clients->deliver(st->clients->dst,buf);
510         }
511         BUF_ASSERT_FREE(buf);
512         return;
513     }
514
515     /* (st->secnet_address needs checking before matching destination
516        addresses) */
517     if (dest==st->secnet_address) {
518         netlink_packet_local(st,client,buf);
519         BUF_ASSERT_FREE(buf);
520         return;
521     }
522     netlink_packet_forward(st,client,buf);
523     BUF_ASSERT_FREE(buf);
524 }
525
526 static void netlink_inst_incoming(void *sst, struct buffer_if *buf)
527 {
528     struct netlink_client *c=sst;
529     struct netlink *st=c->nst;
530
531     netlink_incoming(st,c,buf);
532 }
533
534 static void netlink_dev_incoming(void *sst, struct buffer_if *buf)
535 {
536     struct netlink *st=sst;
537
538     netlink_incoming(st,NULL,buf);
539 }
540
541 static void netlink_set_softlinks(struct netlink *st, struct netlink_client *c,
542                                   bool_t up, uint32_t quality)
543 {
544     uint32_t i;
545
546     if (!st->routes) return; /* Table has not yet been created */
547     for (i=0; i<st->n_routes; i++) {
548         if (st->routes[i].c==c) {
549             st->routes[i].quality=quality;
550             if (!st->routes[i].hard) {
551                 st->routes[i].up=up;
552                 st->set_route(st->dst,&st->routes[i]);
553             }
554         }
555     }
556 }
557
558 static void netlink_set_quality(void *sst, uint32_t quality)
559 {
560     struct netlink_client *c=sst;
561     struct netlink *st=c->nst;
562
563     c->link_quality=quality;
564     if (c->link_quality==LINK_QUALITY_DOWN) {
565         netlink_set_softlinks(st,c,False,c->link_quality);
566     } else {
567         netlink_set_softlinks(st,c,True,c->link_quality);
568     }
569 }
570
571 static void netlink_dump_routes(struct netlink *st, bool_t requested)
572 {
573     int i;
574     string_t net;
575     uint32_t c=M_INFO;
576
577     if (requested) c=M_WARNING;
578     if (st->ptp) {
579         net=ipaddr_to_string(st->secnet_address);
580         Message(c,"%s: point-to-point (remote end is %s); routes:\n",
581                 st->name, net);
582         free(net);
583         for (i=0; i<st->n_routes; i++) {
584             net=subnet_to_string(st->routes[i].net);
585             Message(c,"%s ",net);
586             free(net);
587         }
588         Message(c,"\n");
589     } else {
590         Message(c,"%s: routing table:\n",st->name);
591         for (i=0; i<st->n_routes; i++) {
592             net=subnet_to_string(st->routes[i].net);
593             Message(c,"%s -> tunnel %s (%s,%s route,%s,quality %d,use %d)\n",net,
594                     st->routes[i].c->name,
595                     st->routes[i].hard?"hard":"soft",
596                     st->routes[i].allow_route?"free":"restricted",
597                     st->routes[i].up?"up":"down",
598                     st->routes[i].quality,
599                     st->routes[i].outcount);
600             free(net);
601         }
602         net=ipaddr_to_string(st->secnet_address);
603         Message(c,"%s/32 -> netlink \"%s\" (use %d)\n",
604                 net,st->name,st->localcount);
605         free(net);
606         for (i=0; i<st->subnets->entries; i++) {
607             net=subnet_to_string(st->subnets->list[i]);
608             Message(c,"%s ",net);
609             free(net);
610         }
611         if (i>0)
612             Message(c,"-> host (use %d)\n",st->outcount);
613     }
614 }
615
616 static int netlink_compare_route_specificity(const void *ap, const void *bp)
617 {
618     const struct netlink_route *a=ap;
619     const struct netlink_route *b=bp;
620
621     if (a->net.len==b->net.len) return 0;
622     if (a->net.len<b->net.len) return 1;
623     return -1;
624 }
625
626 static void netlink_phase_hook(void *sst, uint32_t new_phase)
627 {
628     struct netlink *st=sst;
629     struct netlink_client *c;
630     uint32_t i,j;
631
632     /* All the networks serviced by the various tunnels should now
633      * have been registered.  We build a routing table by sorting the
634      * routes into most-specific-first order.  */
635     st->routes=safe_malloc(st->n_routes*sizeof(*st->routes),
636                            "netlink_phase_hook");
637     /* Fill the table */
638     i=0;
639     for (c=st->clients; c; c=c->next) {
640         for (j=0; j<c->subnets->entries; j++) {
641             st->routes[i].net=c->subnets->list[j];
642             st->routes[i].c=c;
643             /* Hard routes are always up;
644                soft routes default to down; routes with no 'deliver' function
645                default to down */
646             st->routes[i].up=c->deliver?
647                 (c->options&OPT_SOFTROUTE?False:True):
648                 False;
649             st->routes[i].kup=False;
650             st->routes[i].hard=c->options&OPT_SOFTROUTE?False:True;
651             st->routes[i].allow_route=c->options&OPT_ALLOWROUTE?
652                 True:False;
653             st->routes[i].quality=c->link_quality;
654             st->routes[i].outcount=0;
655             i++;
656         }
657     }
658     /* ASSERT i==st->n_routes */
659     if (i!=st->n_routes) {
660         fatal("netlink: route count error: expected %d got %d\n",
661               st->n_routes,i);
662     }
663     /* Sort the table in descending order of specificity */
664     qsort(st->routes,st->n_routes,sizeof(*st->routes),
665           netlink_compare_route_specificity);
666
667     netlink_dump_routes(st,False);
668 }
669
670 static void netlink_signal_handler(void *sst, int signum)
671 {
672     struct netlink *st=sst;
673     Message(M_INFO,"%s: route dump requested by SIGUSR1\n",st->name);
674     netlink_dump_routes(st,True);
675 }
676
677 static void netlink_inst_output_config(void *sst, struct buffer_if *buf)
678 {
679 /*    struct netlink_client *c=sst; */
680 /*    struct netlink *st=c->nst; */
681
682     /* For now we don't output anything */
683     BUF_ASSERT_USED(buf);
684 }
685
686 static bool_t netlink_inst_check_config(void *sst, struct buffer_if *buf)
687 {
688 /*    struct netlink_client *c=sst; */
689 /*    struct netlink *st=c->nst; */
690
691     BUF_ASSERT_USED(buf);
692     /* We need to eat all of the configuration information from the buffer
693        for backward compatibility. */
694     buf->size=0;
695     return True;
696 }
697
698 static void netlink_inst_reg(void *sst, netlink_deliver_fn *deliver, 
699                              void *dst, uint32_t max_start_pad,
700                              uint32_t max_end_pad)
701 {
702     struct netlink_client *c=sst;
703     struct netlink *st=c->nst;
704
705     if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
706     if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad;
707     c->deliver=deliver;
708     c->dst=dst;
709 }
710
711 static struct flagstr netlink_option_table[]={
712     { "soft", OPT_SOFTROUTE },
713     { "allow-route", OPT_ALLOWROUTE },
714     { NULL, 0}
715 };
716 /* This is the routine that gets called when the closure that's
717    returned by an invocation of a netlink device closure (eg. tun,
718    userv-ipif) is invoked.  It's used to create routes and pass in
719    information about them; the closure it returns is used by site
720    code.  */
721 static closure_t *netlink_inst_create(struct netlink *st,
722                                       struct cloc loc, dict_t *dict)
723 {
724     struct netlink_client *c;
725     string_t name;
726     struct ipset *networks;
727     uint32_t options;
728     list_t *l;
729
730     name=dict_read_string(dict, "name", True, st->name, loc);
731
732     l=dict_lookup(dict,"routes");
733     if (!l)
734         cfgfatal(loc,st->name,"required parameter \"routes\" not found\n");
735     networks=string_list_to_ipset(l,loc,st->name,"routes");
736     options=string_list_to_word(dict_lookup(dict,"options"),
737                                 netlink_option_table,st->name);
738
739     if ((options&OPT_SOFTROUTE) && !st->set_route) {
740         cfgfatal(loc,st->name,"this netlink device does not support "
741                  "soft routes.\n");
742         return NULL;
743     }
744
745     if (options&OPT_SOFTROUTE) {
746         /* XXX for now we assume that soft routes require root privilege;
747            this may not always be true. The device driver can tell us. */
748         require_root_privileges=True;
749         require_root_privileges_explanation="netlink: soft routes";
750         if (st->ptp) {
751             cfgfatal(loc,st->name,"point-to-point netlinks do not support "
752                      "soft routes.\n");
753             return NULL;
754         }
755     }
756
757     /* Check that nets are a subset of st->remote_networks;
758        refuse to register if they are not. */
759     if (!ipset_is_subset(st->remote_networks,networks)) {
760         cfgfatal(loc,st->name,"routes are not allowed\n");
761         return NULL;
762     }
763
764     c=safe_malloc(sizeof(*c),"netlink_inst_create");
765     c->cl.description=name;
766     c->cl.type=CL_NETLINK;
767     c->cl.apply=NULL;
768     c->cl.interface=&c->ops;
769     c->ops.st=c;
770     c->ops.reg=netlink_inst_reg;
771     c->ops.deliver=netlink_inst_incoming;
772     c->ops.set_quality=netlink_set_quality;
773     c->ops.output_config=netlink_inst_output_config;
774     c->ops.check_config=netlink_inst_check_config;
775     c->nst=st;
776
777     c->networks=networks;
778     c->subnets=ipset_to_subnet_list(networks);
779     c->deliver=NULL;
780     c->dst=NULL;
781     c->name=name;
782     c->options=options;
783     c->link_quality=LINK_QUALITY_DOWN;
784     c->next=st->clients;
785     st->clients=c;
786     st->n_routes+=c->subnets->entries;
787
788     return &c->cl;
789 }
790
791 static list_t *netlink_inst_apply(closure_t *self, struct cloc loc,
792                                   dict_t *context, list_t *args)
793 {
794     struct netlink *st=self->interface;
795
796     dict_t *dict;
797     item_t *item;
798     closure_t *cl;
799
800     item=list_elem(args,0);
801     if (!item || item->type!=t_dict) {
802         cfgfatal(loc,st->name,"must have a dictionary argument\n");
803     }
804     dict=item->data.dict;
805
806     cl=netlink_inst_create(st,loc,dict);
807
808     return new_closure(cl);
809 }
810
811 netlink_deliver_fn *netlink_init(struct netlink *st,
812                                  void *dst, struct cloc loc,
813                                  dict_t *dict, string_t description,
814                                  netlink_route_fn *set_route,
815                                  netlink_deliver_fn *to_host)
816 {
817     item_t *sa, *ptpa;
818     list_t *l;
819
820     st->dst=dst;
821     st->cl.description=description;
822     st->cl.type=CL_PURE;
823     st->cl.apply=netlink_inst_apply;
824     st->cl.interface=st;
825     st->max_start_pad=0;
826     st->max_end_pad=0;
827     st->clients=NULL;
828     st->set_route=set_route;
829     st->deliver_to_host=to_host;
830
831     st->name=dict_read_string(dict,"name",False,description,loc);
832     if (!st->name) st->name=description;
833     l=dict_lookup(dict,"networks");
834     if (l) 
835         st->networks=string_list_to_ipset(l,loc,st->name,"networks");
836     else {
837         Message(M_WARNING,"%s: no local networks (parameter \"networks\") "
838                 "defined\n",st->name);
839         st->networks=ipset_new();
840     }
841     l=dict_lookup(dict,"remote-networks");
842     if (l) {
843         st->remote_networks=string_list_to_ipset(l,loc,st->name,
844                                                  "remote-networks");
845     } else {
846         struct ipset *empty;
847         empty=ipset_new();
848         st->remote_networks=ipset_complement(empty);
849         ipset_free(empty);
850     }
851
852     sa=dict_find_item(dict,"secnet-address",False,"netlink",loc);
853     ptpa=dict_find_item(dict,"ptp-address",False,"netlink",loc);
854     if (sa && ptpa) {
855         cfgfatal(loc,st->name,"you may not specify secnet-address and "
856                  "ptp-address in the same netlink device\n");
857     }
858     if (!(sa || ptpa)) {
859         cfgfatal(loc,st->name,"you must specify secnet-address or "
860                  "ptp-address for this netlink device\n");
861     }
862     if (sa) {
863         st->secnet_address=string_item_to_ipaddr(sa,"netlink");
864         st->ptp=False;
865     } else {
866         st->secnet_address=string_item_to_ipaddr(ptpa,"netlink");
867         st->ptp=True;
868     }
869     /* XXX we may want to subtract secnet_address from networks here, to
870        be strictly correct.  It shouldn't make any practical difference,
871        though, and will make the route dump look complicated... */
872     st->subnets=ipset_to_subnet_list(st->networks);
873     st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
874     buffer_new(&st->icmp,ICMP_BUFSIZE);
875     st->n_routes=0;
876     st->routes=NULL;
877     st->outcount=0;
878     st->localcount=0;
879
880     add_hook(PHASE_SETUP,netlink_phase_hook,st);
881     request_signal_notification(SIGUSR1, netlink_signal_handler, st);
882
883     /* If we're point-to-point then we return a CL_NETLINK directly,
884        rather than a CL_NETLINK_OLD or pure closure (depending on
885        compatibility).  This CL_NETLINK is for our one and only
886        client.  Our cl.apply function is NULL. */
887     if (st->ptp) {
888         closure_t *cl;
889         cl=netlink_inst_create(st,loc,dict);
890         st->cl=*cl;
891     }
892     return netlink_dev_incoming;
893 }
894
895 /* No connection to the kernel at all... */
896
897 struct null {
898     struct netlink nl;
899 };
900
901 static bool_t null_set_route(void *sst, struct netlink_route *route)
902 {
903     struct null *st=sst;
904     string_t t;
905
906     if (route->up!=route->kup) {
907         t=subnet_to_string(route->net);
908         Message(M_INFO,"%s: setting route %s to state %s\n",st->nl.name,
909                 t, route->up?"up":"down");
910         free(t);
911         route->kup=route->up;
912         return True;
913     }
914     return False;
915 }
916             
917 static void null_deliver(void *sst, struct buffer_if *buf)
918 {
919     return;
920 }
921
922 static list_t *null_apply(closure_t *self, struct cloc loc, dict_t *context,
923                           list_t *args)
924 {
925     struct null *st;
926     item_t *item;
927     dict_t *dict;
928
929     st=safe_malloc(sizeof(*st),"null_apply");
930
931     item=list_elem(args,0);
932     if (!item || item->type!=t_dict)
933         cfgfatal(loc,"null-netlink","parameter must be a dictionary\n");
934     
935     dict=item->data.dict;
936
937     netlink_init(&st->nl,st,loc,dict,"null-netlink",null_set_route,
938                  null_deliver);
939
940     return new_closure(&st->nl.cl);
941 }
942
943 init_module netlink_module;
944 void netlink_module(dict_t *dict)
945 {
946     add_closure(dict,"null-netlink",null_apply);
947 }