chiark / gitweb /
build system: Include signing of tarballs in release checklist
[secnet.git] / netlink.c
1 /* User-kernel network link */
2
3 /* See RFCs 791, 792, 1123 and 1812 */
4
5 /* The netlink device is actually a router.  Tunnels are unnumbered
6    point-to-point lines (RFC1812 section 2.2.7); the router has a
7    single address (the 'router-id'). */
8
9 /* This is where we currently have the anti-spoofing paranoia - before
10    sending a packet to the kernel we check that the tunnel it came
11    over could reasonably have produced it. */
12
13
14 /* Points to note from RFC1812 (which may require changes in this
15    file):
16
17 3.3.4 Maximum Transmission Unit - MTU
18
19    The MTU of each logical interface MUST be configurable within the
20    range of legal MTUs for the interface.
21
22    Many Link Layer protocols define a maximum frame size that may be
23    sent.  In such cases, a router MUST NOT allow an MTU to be set which
24    would allow sending of frames larger than those allowed by the Link
25    Layer protocol.  However, a router SHOULD be willing to receive a
26    packet as large as the maximum frame size even if that is larger than
27    the MTU.
28
29 4.2.1  A router SHOULD count datagrams discarded.
30
31 4.2.2.1 Source route options - we probably should implement processing
32 of source routes, even though mostly the security policy will prevent
33 their use.
34
35 5.3.13.4 Source Route Options
36
37    A router MUST implement support for source route options in forwarded
38    packets.  A router MAY implement a configuration option that, when
39    enabled, causes all source-routed packets to be discarded.  However,
40    such an option MUST NOT be enabled by default.
41
42 5.3.13.5 Record Route Option
43
44    Routers MUST support the Record Route option in forwarded packets.
45
46    A router MAY provide a configuration option that, if enabled, will
47    cause the router to ignore (i.e., pass through unchanged) Record
48    Route options in forwarded packets.  If provided, such an option MUST
49    default to enabling the record-route.  This option should not affect
50    the processing of Record Route options in datagrams received by the
51    router itself (in particular, Record Route options in ICMP echo
52    requests will still be processed according to Section [4.3.3.6]).
53
54 5.3.13.6 Timestamp Option
55
56    Routers MUST support the timestamp option in forwarded packets.  A
57    timestamp value MUST follow the rules given [INTRO:2].
58
59    If the flags field = 3 (timestamp and prespecified address), the
60    router MUST add its timestamp if the next prespecified address
61    matches any of the router's IP addresses.  It is not necessary that
62    the prespecified address be either the address of the interface on
63    which the packet arrived or the address of the interface over which
64    it will be sent.
65
66
67 4.2.2.7 Fragmentation: RFC 791 Section 3.2
68
69    Fragmentation, as described in [INTERNET:1], MUST be supported by a
70    router.
71
72 4.2.2.8 Reassembly: RFC 791 Section 3.2
73
74    As specified in the corresponding section of [INTRO:2], a router MUST
75    support reassembly of datagrams that it delivers to itself.
76
77 4.2.2.9 Time to Live: RFC 791 Section 3.2
78
79    Note in particular that a router MUST NOT check the TTL of a packet
80    except when forwarding it.
81
82    A router MUST NOT discard a datagram just because it was received
83    with TTL equal to zero or one; if it is to the router and otherwise
84    valid, the router MUST attempt to receive it.
85
86    On messages the router originates, the IP layer MUST provide a means
87    for the transport layer to set the TTL field of every datagram that
88    is sent.  When a fixed TTL value is used, it MUST be configurable.
89
90
91 8.1 The Simple Network Management Protocol - SNMP
92 8.1.1 SNMP Protocol Elements
93
94    Routers MUST be manageable by SNMP [MGT:3].  The SNMP MUST operate
95    using UDP/IP as its transport and network protocols.
96
97
98 */
99
100 #include <string.h>
101 #include <assert.h>
102 #include <limits.h>
103 #include "secnet.h"
104 #include "util.h"
105 #include "ipaddr.h"
106 #include "netlink.h"
107 #include "process.h"
108
109 #define OPT_SOFTROUTE   1
110 #define OPT_ALLOWROUTE  2
111
112 #define ICMP_TYPE_ECHO_REPLY             0
113
114 #define ICMP_TYPE_UNREACHABLE            3
115 #define ICMP_CODE_NET_UNREACHABLE        0
116 #define ICMP_CODE_PROTOCOL_UNREACHABLE   2
117 #define ICMP_CODE_FRAGMENTATION_REQUIRED 4
118 #define ICMP_CODE_NET_PROHIBITED        13
119
120 #define ICMP_TYPE_ECHO_REQUEST           8
121
122 #define ICMP_TYPE_TIME_EXCEEDED         11
123 #define ICMP_CODE_TTL_EXCEEDED           0
124
125 /* Generic IP checksum routine */
126 static inline uint16_t ip_csum(uint8_t *iph,int32_t count)
127 {
128     register uint32_t sum=0;
129
130     while (count>1) {
131         sum+=ntohs(*(uint16_t *)iph);
132         iph+=2;
133         count-=2;
134     }
135     if(count>0)
136         sum+=*(uint8_t *)iph;
137     while (sum>>16)
138         sum=(sum&0xffff)+(sum>>16);
139     return htons(~sum);
140 }
141
142 #ifdef i386
143 /*
144  *      This is a version of ip_compute_csum() optimized for IP headers,
145  *      which always checksum on 4 octet boundaries.
146  *
147  *      By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
148  *      Arnt Gulbrandsen.
149  */
150 static inline uint16_t ip_fast_csum(uint8_t *iph, int32_t ihl) {
151     uint32_t sum;
152
153     __asm__ __volatile__(
154             "movl (%1), %0      ;\n"
155             "subl $4, %2        ;\n"
156             "jbe 2f             ;\n"
157             "addl 4(%1), %0     ;\n"
158             "adcl 8(%1), %0     ;\n"
159             "adcl 12(%1), %0    ;\n"
160 "1:         adcl 16(%1), %0     ;\n"
161             "lea 4(%1), %1      ;\n"
162             "decl %2            ;\n"
163             "jne 1b             ;\n"
164             "adcl $0, %0        ;\n"
165             "movl %0, %2        ;\n"
166             "shrl $16, %0       ;\n"
167             "addw %w2, %w0      ;\n"
168             "adcl $0, %0        ;\n"
169             "notl %0            ;\n"
170 "2:                             ;\n"
171         /* Since the input registers which are loaded with iph and ipl
172            are modified, we must also specify them as outputs, or gcc
173            will assume they contain their original values. */
174         : "=r" (sum), "=r" (iph), "=r" (ihl)
175         : "1" (iph), "2" (ihl)
176         : "memory");
177     return sum;
178 }
179 #else
180 static inline uint16_t ip_fast_csum(uint8_t *iph, int32_t ihl)
181 {
182     assert(ihl < INT_MAX/4);
183     return ip_csum(iph,ihl*4);
184 }
185 #endif
186
187 struct iphdr {
188 #if defined (WORDS_BIGENDIAN)
189     uint8_t    version:4,
190                ihl:4;
191 #else
192     uint8_t    ihl:4,
193                version:4;
194 #endif
195     uint8_t    tos;
196     uint16_t   tot_len;
197     uint16_t   id;
198     uint16_t   frag_off;
199     uint8_t    ttl;
200     uint8_t    protocol;
201     uint16_t   check;
202     uint32_t   saddr;
203     uint32_t   daddr;
204     /* The options start here. */
205 };
206
207 struct icmphdr {
208     struct iphdr iph;
209     uint8_t type;
210     uint8_t code;
211     uint16_t check;
212     union {
213         uint32_t unused;
214         struct {
215             uint8_t pointer;
216             uint8_t unused1;
217             uint16_t unused2;
218         } pprob;
219         uint32_t gwaddr;
220         struct {
221             uint16_t id;
222             uint16_t seq;
223         } echo;
224     } d;
225 };
226     
227 static void netlink_packet_deliver(struct netlink *st,
228                                    struct netlink_client *client,
229                                    struct buffer_if *buf);
230
231 /* XXX RFC1812 4.3.2.5:
232    All other ICMP error messages (Destination Unreachable,
233    Redirect, Time Exceeded, and Parameter Problem) SHOULD have their
234    precedence value set to 6 (INTERNETWORK CONTROL) or 7 (NETWORK
235    CONTROL).  The IP Precedence value for these error messages MAY be
236    settable.
237    */
238 static struct icmphdr *netlink_icmp_tmpl(struct netlink *st,
239                                          uint32_t dest,uint16_t len)
240 {
241     struct icmphdr *h;
242
243     BUF_ALLOC(&st->icmp,"netlink_icmp_tmpl");
244     buffer_init(&st->icmp,st->max_start_pad);
245     h=buf_append(&st->icmp,sizeof(*h));
246
247     h->iph.version=4;
248     h->iph.ihl=5;
249     h->iph.tos=0;
250     h->iph.tot_len=htons(len+(h->iph.ihl*4)+8);
251     h->iph.id=0;
252     h->iph.frag_off=0;
253     h->iph.ttl=255; /* XXX should be configurable */
254     h->iph.protocol=1;
255     h->iph.saddr=htonl(st->secnet_address);
256     h->iph.daddr=htonl(dest);
257     h->iph.check=0;
258     h->iph.check=ip_fast_csum((uint8_t *)&h->iph,h->iph.ihl);
259     h->check=0;
260     h->d.unused=0;
261
262     return h;
263 }
264
265 /* Fill in the ICMP checksum field correctly */
266 static void netlink_icmp_csum(struct icmphdr *h)
267 {
268     int32_t len;
269
270     len=ntohs(h->iph.tot_len)-(4*h->iph.ihl);
271     h->check=0;
272     h->check=ip_csum(&h->type,len);
273 }
274
275 /* RFC1122:
276  *       An ICMP error message MUST NOT be sent as the result of
277  *       receiving:
278  *
279  *       *    an ICMP error message, or
280  *
281  *       *    a datagram destined to an IP broadcast or IP multicast
282  *            address, or
283  *
284  *       *    a datagram sent as a link-layer broadcast, or
285  *
286  *       *    a non-initial fragment, or
287  *
288  *       *    a datagram whose source address does not define a single
289  *            host -- e.g., a zero address, a loopback address, a
290  *            broadcast address, a multicast address, or a Class E
291  *            address.
292  */
293 static bool_t netlink_icmp_may_reply(struct buffer_if *buf)
294 {
295     struct iphdr *iph;
296     struct icmphdr *icmph;
297     uint32_t source;
298
299     iph=(struct iphdr *)buf->start;
300     icmph=(struct icmphdr *)buf->start;
301     if (iph->protocol==1) {
302         switch(icmph->type) {
303         case 3: /* Destination unreachable */
304         case 11: /* Time Exceeded */
305         case 12: /* Parameter Problem */
306             return False;
307         }
308     }
309     /* How do we spot broadcast destination addresses? */
310     if (ntohs(iph->frag_off)&0x1fff) return False; /* Non-initial fragment */
311     source=ntohl(iph->saddr);
312     if (source==0) return False;
313     if ((source&0xff000000)==0x7f000000) return False;
314     /* How do we spot broadcast source addresses? */
315     if ((source&0xf0000000)==0xe0000000) return False; /* Multicast */
316     if ((source&0xf0000000)==0xf0000000) return False; /* Class E */
317     return True;
318 }
319
320 /* How much of the original IP packet do we include in its ICMP
321    response? The header plus up to 64 bits. */
322
323 /* XXX TODO RFC1812:
324 4.3.2.3 Original Message Header
325
326    Historically, every ICMP error message has included the Internet
327    header and at least the first 8 data bytes of the datagram that
328    triggered the error.  This is no longer adequate, due to the use of
329    IP-in-IP tunneling and other technologies.  Therefore, the ICMP
330    datagram SHOULD contain as much of the original datagram as possible
331    without the length of the ICMP datagram exceeding 576 bytes.  The
332    returned IP header (and user data) MUST be identical to that which
333    was received, except that the router is not required to undo any
334    modifications to the IP header that are normally performed in
335    forwarding that were performed before the error was detected (e.g.,
336    decrementing the TTL, or updating options).  Note that the
337    requirements of Section [4.3.3.5] supersede this requirement in some
338    cases (i.e., for a Parameter Problem message, if the problem is in a
339    modified field, the router must undo the modification).  See Section
340    [4.3.3.5]).
341    */
342 static uint16_t netlink_icmp_reply_len(struct buffer_if *buf)
343 {
344     struct iphdr *iph=(struct iphdr *)buf->start;
345     uint16_t hlen,plen;
346
347     hlen=iph->ihl*4;
348     /* We include the first 8 bytes of the packet data, provided they exist */
349     hlen+=8;
350     plen=ntohs(iph->tot_len);
351     return (hlen>plen?plen:hlen);
352 }
353
354 /* client indicates where the packet we're constructing a response to
355    comes from. NULL indicates the host. */
356 static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf,
357                                 struct netlink_client *client,
358                                 uint8_t type, uint8_t code)
359 {
360     struct iphdr *iph=(struct iphdr *)buf->start;
361     struct icmphdr *h;
362     uint16_t len;
363
364     if (netlink_icmp_may_reply(buf)) {
365         len=netlink_icmp_reply_len(buf);
366         h=netlink_icmp_tmpl(st,ntohl(iph->saddr),len);
367         h->type=type; h->code=code;
368         memcpy(buf_append(&st->icmp,len),buf->start,len);
369         netlink_icmp_csum(h);
370         netlink_packet_deliver(st,NULL,&st->icmp);
371         BUF_ASSERT_FREE(&st->icmp);
372     }
373 }
374
375 /*
376  * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the
377  * checksum.
378  * RFC1812: 4.2.2.5 MUST discard messages containing invalid checksums.
379  *
380  * Is the datagram acceptable?
381  *
382  * 1. Length at least the size of an ip header
383  * 2. Version of 4
384  * 3. Checksums correctly.
385  * 4. Doesn't have a bogus length
386  */
387 static bool_t netlink_check(struct netlink *st, struct buffer_if *buf)
388 {
389     struct iphdr *iph=(struct iphdr *)buf->start;
390     int32_t len;
391
392     if (iph->ihl < 5 || iph->version != 4) return False;
393     if (buf->size < iph->ihl*4) return False;
394     if (ip_fast_csum((uint8_t *)iph, iph->ihl)!=0) return False;
395     len=ntohs(iph->tot_len);
396     /* There should be no padding */
397     if (buf->size!=len || len<(iph->ihl<<2)) return False;
398     /* XXX check that there's no source route specified */
399     return True;
400 }
401
402 /* Deliver a packet. "client" is the _origin_ of the packet, not its
403    destination, and is NULL for packets from the host and packets
404    generated internally in secnet.  */
405 static void netlink_packet_deliver(struct netlink *st,
406                                    struct netlink_client *client,
407                                    struct buffer_if *buf)
408 {
409     struct iphdr *iph=(struct iphdr *)buf->start;
410     uint32_t dest=ntohl(iph->daddr);
411     uint32_t source=ntohl(iph->saddr);
412     uint32_t best_quality;
413     bool_t allow_route=False;
414     bool_t found_allowed=False;
415     int best_match;
416     int i;
417
418     BUF_ASSERT_USED(buf);
419
420     if (dest==st->secnet_address) {
421         Message(M_ERR,"%s: trying to deliver a packet to myself!\n",st->name);
422         BUF_FREE(buf);
423         return;
424     }
425     
426     /* Packets from the host (client==NULL) may always be routed.  Packets
427        from clients with the allow_route option will also be routed. */
428     if (!client || (client && (client->options & OPT_ALLOWROUTE)))
429         allow_route=True;
430
431     /* If !allow_route, we check the routing table anyway, and if
432        there's a suitable route with OPT_ALLOWROUTE set we use it.  If
433        there's a suitable route, but none with OPT_ALLOWROUTE set then
434        we generate ICMP 'communication with destination network
435        administratively prohibited'. */
436
437     best_quality=0;
438     best_match=-1;
439     for (i=0; i<st->n_clients; i++) {
440         if (st->routes[i]->up &&
441             ipset_contains_addr(st->routes[i]->networks,dest)) {
442             /* It's an available route to the correct destination. But is
443                it better than the one we already have? */
444
445             /* If we have already found an allowed route then we don't
446                bother looking at routes we're not allowed to use.  If
447                we don't yet have an allowed route we'll consider any.  */
448             if (!allow_route && found_allowed) {
449                 if (!(st->routes[i]->options&OPT_ALLOWROUTE)) continue;
450             }
451             
452             if (st->routes[i]->link_quality>best_quality
453                 || best_quality==0) {
454                 best_quality=st->routes[i]->link_quality;
455                 best_match=i;
456                 if (st->routes[i]->options&OPT_ALLOWROUTE)
457                     found_allowed=True;
458                 /* If quality isn't perfect we may wish to
459                    consider kicking the tunnel with a 0-length
460                    packet to prompt it to perform a key setup.
461                    Then it'll eventually decide it's up or
462                    down. */
463                 /* If quality is perfect and we're allowed to use the
464                    route we don't need to search any more. */
465                 if (best_quality>=MAXIMUM_LINK_QUALITY && 
466                     (allow_route || found_allowed)) break;
467             }
468         }
469     }
470     if (best_match==-1) {
471         /* The packet's not going down a tunnel.  It might (ought to)
472            be for the host.   */
473         if (ipset_contains_addr(st->networks,dest)) {
474             st->deliver_to_host(st->dst,buf);
475             st->outcount++;
476             BUF_ASSERT_FREE(buf);
477         } else {
478             string_t s,d;
479             s=ipaddr_to_string(source);
480             d=ipaddr_to_string(dest);
481             Message(M_DEBUG,"%s: don't know where to deliver packet "
482                     "(s=%s, d=%s)\n", st->name, s, d);
483             free(s); free(d);
484             netlink_icmp_simple(st,buf,client,ICMP_TYPE_UNREACHABLE,
485                                 ICMP_CODE_NET_UNREACHABLE);
486             BUF_FREE(buf);
487         }
488     } else {
489         if (!allow_route &&
490             !(st->routes[best_match]->options&OPT_ALLOWROUTE)) {
491             string_t s,d;
492             s=ipaddr_to_string(source);
493             d=ipaddr_to_string(dest);
494             /* We have a usable route but aren't allowed to use it.
495                Generate ICMP destination unreachable: communication
496                with destination network administratively prohibited */
497             Message(M_NOTICE,"%s: denied forwarding for packet (s=%s, d=%s)\n",
498                     st->name,s,d);
499             free(s); free(d);
500                     
501             netlink_icmp_simple(st,buf,client,ICMP_TYPE_UNREACHABLE,
502                                 ICMP_CODE_NET_PROHIBITED);
503             BUF_FREE(buf);
504         } else {
505             if (best_quality>0) {
506                 /* XXX Fragment if required */
507                 st->routes[best_match]->deliver(
508                     st->routes[best_match]->dst, buf);
509                 st->routes[best_match]->outcount++;
510                 BUF_ASSERT_FREE(buf);
511             } else {
512                 /* Generate ICMP destination unreachable */
513                 netlink_icmp_simple(st,buf,client,ICMP_TYPE_UNREACHABLE,
514                                     ICMP_CODE_NET_UNREACHABLE); /* client==NULL */
515                 BUF_FREE(buf);
516             }
517         }
518     }
519     BUF_ASSERT_FREE(buf);
520 }
521
522 static void netlink_packet_forward(struct netlink *st, 
523                                    struct netlink_client *client,
524                                    struct buffer_if *buf)
525 {
526     struct iphdr *iph=(struct iphdr *)buf->start;
527     
528     BUF_ASSERT_USED(buf);
529
530     /* Packet has already been checked */
531     if (iph->ttl<=1) {
532         /* Generate ICMP time exceeded */
533         netlink_icmp_simple(st,buf,client,ICMP_TYPE_TIME_EXCEEDED,
534                             ICMP_CODE_TTL_EXCEEDED);
535         BUF_FREE(buf);
536         return;
537     }
538     iph->ttl--;
539     iph->check=0;
540     iph->check=ip_fast_csum((uint8_t *)iph,iph->ihl);
541
542     netlink_packet_deliver(st,client,buf);
543     BUF_ASSERT_FREE(buf);
544 }
545
546 /* Deal with packets addressed explicitly to us */
547 static void netlink_packet_local(struct netlink *st,
548                                  struct netlink_client *client,
549                                  struct buffer_if *buf)
550 {
551     struct icmphdr *h;
552
553     st->localcount++;
554
555     h=(struct icmphdr *)buf->start;
556
557     if ((ntohs(h->iph.frag_off)&0xbfff)!=0) {
558         Message(M_WARNING,"%s: fragmented packet addressed to secnet; "
559                 "ignoring it\n",st->name);
560         BUF_FREE(buf);
561         return;
562     }
563
564     if (h->iph.protocol==1) {
565         /* It's ICMP */
566         if (h->type==ICMP_TYPE_ECHO_REQUEST && h->code==0) {
567             /* ICMP echo-request. Special case: we re-use the buffer
568                to construct the reply. */
569             h->type=ICMP_TYPE_ECHO_REPLY;
570             h->iph.daddr=h->iph.saddr;
571             h->iph.saddr=htonl(st->secnet_address);
572             h->iph.ttl=255;
573             h->iph.check=0;
574             h->iph.check=ip_fast_csum((uint8_t *)h,h->iph.ihl);
575             netlink_icmp_csum(h);
576             netlink_packet_deliver(st,NULL,buf);
577             return;
578         }
579         Message(M_WARNING,"%s: unknown incoming ICMP\n",st->name);
580     } else {
581         /* Send ICMP protocol unreachable */
582         netlink_icmp_simple(st,buf,client,ICMP_TYPE_UNREACHABLE,
583                             ICMP_CODE_PROTOCOL_UNREACHABLE);
584         BUF_FREE(buf);
585         return;
586     }
587
588     BUF_FREE(buf);
589 }
590
591 /* If cid==NULL packet is from host, otherwise cid specifies which tunnel 
592    it came from. */
593 static void netlink_incoming(struct netlink *st, struct netlink_client *client,
594                              struct buffer_if *buf)
595 {
596     uint32_t source,dest;
597     struct iphdr *iph;
598
599     BUF_ASSERT_USED(buf);
600     if (!netlink_check(st,buf)) {
601         Message(M_WARNING,"%s: bad IP packet from %s\n",
602                 st->name,client?client->name:"host");
603         BUF_FREE(buf);
604         return;
605     }
606     iph=(struct iphdr *)buf->start;
607
608     source=ntohl(iph->saddr);
609     dest=ntohl(iph->daddr);
610
611     /* Check source. If we don't like the source, there's no point
612        generating ICMP because we won't know how to get it to the
613        source of the packet. */
614     if (client) {
615         /* Check that the packet source is appropriate for the tunnel
616            it came down */
617         if (!ipset_contains_addr(client->networks,source)) {
618             string_t s,d;
619             s=ipaddr_to_string(source);
620             d=ipaddr_to_string(dest);
621             Message(M_WARNING,"%s: packet from tunnel %s with bad "
622                     "source address (s=%s,d=%s)\n",st->name,client->name,s,d);
623             free(s); free(d);
624             BUF_FREE(buf);
625             return;
626         }
627     } else {
628         /* Check that the packet originates in our configured local
629            network, and hasn't been forwarded from elsewhere or
630            generated with the wrong source address */
631         if (!ipset_contains_addr(st->networks,source)) {
632             string_t s,d;
633             s=ipaddr_to_string(source);
634             d=ipaddr_to_string(dest);
635             Message(M_WARNING,"%s: outgoing packet with bad source address "
636                     "(s=%s,d=%s)\n",st->name,s,d);
637             free(s); free(d);
638             BUF_FREE(buf);
639             return;
640         }
641     }
642
643     /* If this is a point-to-point device we don't examine the
644        destination address at all; we blindly send it down our
645        one-and-only registered tunnel, or to the host, depending on
646        where it came from.  It's up to external software to check
647        address validity and generate ICMP, etc. */
648     if (st->ptp) {
649         if (client) {
650             st->deliver_to_host(st->dst,buf);
651         } else {
652             st->clients->deliver(st->clients->dst,buf);
653         }
654         BUF_ASSERT_FREE(buf);
655         return;
656     }
657
658     /* st->secnet_address needs checking before matching destination
659        addresses */
660     if (dest==st->secnet_address) {
661         netlink_packet_local(st,client,buf);
662         BUF_ASSERT_FREE(buf);
663         return;
664     }
665     netlink_packet_forward(st,client,buf);
666     BUF_ASSERT_FREE(buf);
667 }
668
669 static void netlink_inst_incoming(void *sst, struct buffer_if *buf)
670 {
671     struct netlink_client *c=sst;
672     struct netlink *st=c->nst;
673
674     netlink_incoming(st,c,buf);
675 }
676
677 static void netlink_dev_incoming(void *sst, struct buffer_if *buf)
678 {
679     struct netlink *st=sst;
680
681     netlink_incoming(st,NULL,buf);
682 }
683
684 static void netlink_set_quality(void *sst, uint32_t quality)
685 {
686     struct netlink_client *c=sst;
687     struct netlink *st=c->nst;
688
689     c->link_quality=quality;
690     c->up=(c->link_quality==LINK_QUALITY_DOWN)?False:True;
691     if (c->options&OPT_SOFTROUTE) {
692         st->set_routes(st->dst,c);
693     }
694 }
695
696 static void netlink_output_subnets(struct netlink *st, uint32_t loglevel,
697                                    struct subnet_list *snets)
698 {
699     int32_t i;
700     string_t net;
701
702     for (i=0; i<snets->entries; i++) {
703         net=subnet_to_string(snets->list[i]);
704         Message(loglevel,"%s ",net);
705         free(net);
706     }
707 }
708
709 static void netlink_dump_routes(struct netlink *st, bool_t requested)
710 {
711     int i;
712     string_t net;
713     uint32_t c=M_INFO;
714
715     if (requested) c=M_WARNING;
716     if (st->ptp) {
717         net=ipaddr_to_string(st->secnet_address);
718         Message(c,"%s: point-to-point (remote end is %s); routes:\n",
719                 st->name, net);
720         free(net);
721         netlink_output_subnets(st,c,st->clients->subnets);
722         Message(c,"\n");
723     } else {
724         Message(c,"%s: routing table:\n",st->name);
725         for (i=0; i<st->n_clients; i++) {
726             netlink_output_subnets(st,c,st->routes[i]->subnets);
727             Message(c,"-> tunnel %s (%s,mtu %d,%s routes,%s,"
728                     "quality %d,use %d,pri %lu)\n",
729                     st->routes[i]->name,
730                     st->routes[i]->up?"up":"down",
731                     st->routes[i]->mtu,
732                     st->routes[i]->options&OPT_SOFTROUTE?"soft":"hard",
733                     st->routes[i]->options&OPT_ALLOWROUTE?"free":"restricted",
734                     st->routes[i]->link_quality,
735                     st->routes[i]->outcount,
736                     (unsigned long)st->routes[i]->priority);
737         }
738         net=ipaddr_to_string(st->secnet_address);
739         Message(c,"%s/32 -> netlink \"%s\" (use %d)\n",
740                 net,st->name,st->localcount);
741         free(net);
742         for (i=0; i<st->subnets->entries; i++) {
743             net=subnet_to_string(st->subnets->list[i]);
744             Message(c,"%s ",net);
745             free(net);
746         }
747         if (i>0)
748             Message(c,"-> host (use %d)\n",st->outcount);
749     }
750 }
751
752 /* ap is a pointer to a member of the routes array */
753 static int netlink_compare_client_priority(const void *ap, const void *bp)
754 {
755     const struct netlink_client *const*a=ap;
756     const struct netlink_client *const*b=bp;
757
758     if ((*a)->priority==(*b)->priority) return 0;
759     if ((*a)->priority<(*b)->priority) return 1;
760     return -1;
761 }
762
763 static void netlink_phase_hook(void *sst, uint32_t new_phase)
764 {
765     struct netlink *st=sst;
766     struct netlink_client *c;
767     int32_t i;
768
769     /* All the networks serviced by the various tunnels should now
770      * have been registered.  We build a routing table by sorting the
771      * clients by priority.  */
772     st->routes=safe_malloc_ary(sizeof(*st->routes),st->n_clients,
773                                "netlink_phase_hook");
774     /* Fill the table */
775     i=0;
776     for (c=st->clients; c; c=c->next) {
777         assert(i<INT_MAX);
778         st->routes[i++]=c;
779     }
780     /* Sort the table in descending order of priority */
781     qsort(st->routes,st->n_clients,sizeof(*st->routes),
782           netlink_compare_client_priority);
783
784     netlink_dump_routes(st,False);
785 }
786
787 static void netlink_signal_handler(void *sst, int signum)
788 {
789     struct netlink *st=sst;
790     Message(M_INFO,"%s: route dump requested by SIGUSR1\n",st->name);
791     netlink_dump_routes(st,True);
792 }
793
794 static void netlink_inst_output_config(void *sst, struct buffer_if *buf)
795 {
796 /*    struct netlink_client *c=sst; */
797 /*    struct netlink *st=c->nst; */
798
799     /* For now we don't output anything */
800     BUF_ASSERT_USED(buf);
801 }
802
803 static bool_t netlink_inst_check_config(void *sst, struct buffer_if *buf)
804 {
805 /*    struct netlink_client *c=sst; */
806 /*    struct netlink *st=c->nst; */
807
808     BUF_ASSERT_USED(buf);
809     /* We need to eat all of the configuration information from the buffer
810        for backward compatibility. */
811     buf->size=0;
812     return True;
813 }
814
815 static void netlink_inst_set_mtu(void *sst, int32_t new_mtu)
816 {
817     struct netlink_client *c=sst;
818
819     c->mtu=new_mtu;
820 }
821
822 static void netlink_inst_reg(void *sst, netlink_deliver_fn *deliver, 
823                              void *dst, int32_t max_start_pad,
824                              int32_t max_end_pad)
825 {
826     struct netlink_client *c=sst;
827     struct netlink *st=c->nst;
828
829     if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
830     if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad;
831     c->deliver=deliver;
832     c->dst=dst;
833 }
834
835 static struct flagstr netlink_option_table[]={
836     { "soft", OPT_SOFTROUTE },
837     { "allow-route", OPT_ALLOWROUTE },
838     { NULL, 0}
839 };
840 /* This is the routine that gets called when the closure that's
841    returned by an invocation of a netlink device closure (eg. tun,
842    userv-ipif) is invoked.  It's used to create routes and pass in
843    information about them; the closure it returns is used by site
844    code.  */
845 static closure_t *netlink_inst_create(struct netlink *st,
846                                       struct cloc loc, dict_t *dict)
847 {
848     struct netlink_client *c;
849     string_t name;
850     struct ipset *networks;
851     uint32_t options,priority;
852     int32_t mtu;
853     list_t *l;
854
855     name=dict_read_string(dict, "name", True, st->name, loc);
856
857     l=dict_lookup(dict,"routes");
858     if (!l)
859         cfgfatal(loc,st->name,"required parameter \"routes\" not found\n");
860     networks=string_list_to_ipset(l,loc,st->name,"routes");
861     options=string_list_to_word(dict_lookup(dict,"options"),
862                                 netlink_option_table,st->name);
863
864     priority=dict_read_number(dict,"priority",False,st->name,loc,0);
865     mtu=dict_read_number(dict,"mtu",False,st->name,loc,0);
866
867     if ((options&OPT_SOFTROUTE) && !st->set_routes) {
868         cfgfatal(loc,st->name,"this netlink device does not support "
869                  "soft routes.\n");
870         return NULL;
871     }
872
873     if (options&OPT_SOFTROUTE) {
874         /* XXX for now we assume that soft routes require root privilege;
875            this may not always be true. The device driver can tell us. */
876         require_root_privileges=True;
877         require_root_privileges_explanation="netlink: soft routes";
878         if (st->ptp) {
879             cfgfatal(loc,st->name,"point-to-point netlinks do not support "
880                      "soft routes.\n");
881             return NULL;
882         }
883     }
884
885     /* Check that nets are a subset of st->remote_networks;
886        refuse to register if they are not. */
887     if (!ipset_is_subset(st->remote_networks,networks)) {
888         cfgfatal(loc,st->name,"routes are not allowed\n");
889         return NULL;
890     }
891
892     c=safe_malloc(sizeof(*c),"netlink_inst_create");
893     c->cl.description=name;
894     c->cl.type=CL_NETLINK;
895     c->cl.apply=NULL;
896     c->cl.interface=&c->ops;
897     c->ops.st=c;
898     c->ops.reg=netlink_inst_reg;
899     c->ops.deliver=netlink_inst_incoming;
900     c->ops.set_quality=netlink_set_quality;
901     c->ops.output_config=netlink_inst_output_config;
902     c->ops.check_config=netlink_inst_check_config;
903     c->ops.set_mtu=netlink_inst_set_mtu;
904     c->nst=st;
905
906     c->networks=networks;
907     c->subnets=ipset_to_subnet_list(networks);
908     c->priority=priority;
909     c->deliver=NULL;
910     c->dst=NULL;
911     c->name=name;
912     c->link_quality=LINK_QUALITY_DOWN;
913     c->mtu=mtu?mtu:st->mtu;
914     c->options=options;
915     c->outcount=0;
916     c->up=False;
917     c->kup=False;
918     c->next=st->clients;
919     st->clients=c;
920     assert(st->n_clients < INT_MAX);
921     st->n_clients++;
922
923     return &c->cl;
924 }
925
926 static list_t *netlink_inst_apply(closure_t *self, struct cloc loc,
927                                   dict_t *context, list_t *args)
928 {
929     struct netlink *st=self->interface;
930
931     dict_t *dict;
932     item_t *item;
933     closure_t *cl;
934
935     item=list_elem(args,0);
936     if (!item || item->type!=t_dict) {
937         cfgfatal(loc,st->name,"must have a dictionary argument\n");
938     }
939     dict=item->data.dict;
940
941     cl=netlink_inst_create(st,loc,dict);
942
943     return new_closure(cl);
944 }
945
946 netlink_deliver_fn *netlink_init(struct netlink *st,
947                                  void *dst, struct cloc loc,
948                                  dict_t *dict, cstring_t description,
949                                  netlink_route_fn *set_routes,
950                                  netlink_deliver_fn *to_host)
951 {
952     item_t *sa, *ptpa;
953     list_t *l;
954
955     st->dst=dst;
956     st->cl.description=description;
957     st->cl.type=CL_PURE;
958     st->cl.apply=netlink_inst_apply;
959     st->cl.interface=st;
960     st->max_start_pad=0;
961     st->max_end_pad=0;
962     st->clients=NULL;
963     st->routes=NULL;
964     st->n_clients=0;
965     st->set_routes=set_routes;
966     st->deliver_to_host=to_host;
967
968     st->name=dict_read_string(dict,"name",False,description,loc);
969     if (!st->name) st->name=description;
970     l=dict_lookup(dict,"networks");
971     if (l) 
972         st->networks=string_list_to_ipset(l,loc,st->name,"networks");
973     else {
974         struct ipset *empty;
975         empty=ipset_new();
976         st->networks=ipset_complement(empty);
977         ipset_free(empty);
978     }
979     l=dict_lookup(dict,"remote-networks");
980     if (l) {
981         st->remote_networks=string_list_to_ipset(l,loc,st->name,
982                                                  "remote-networks");
983     } else {
984         struct ipset *empty;
985         empty=ipset_new();
986         st->remote_networks=ipset_complement(empty);
987         ipset_free(empty);
988     }
989
990     sa=dict_find_item(dict,"secnet-address",False,"netlink",loc);
991     ptpa=dict_find_item(dict,"ptp-address",False,"netlink",loc);
992     if (sa && ptpa) {
993         cfgfatal(loc,st->name,"you may not specify secnet-address and "
994                  "ptp-address in the same netlink device\n");
995     }
996     if (!(sa || ptpa)) {
997         cfgfatal(loc,st->name,"you must specify secnet-address or "
998                  "ptp-address for this netlink device\n");
999     }
1000     if (sa) {
1001         st->secnet_address=string_item_to_ipaddr(sa,"netlink");
1002         st->ptp=False;
1003     } else {
1004         st->secnet_address=string_item_to_ipaddr(ptpa,"netlink");
1005         st->ptp=True;
1006     }
1007     /* To be strictly correct we could subtract secnet_address from
1008        networks here.  It shouldn't make any practical difference,
1009        though, and will make the route dump look complicated... */
1010     st->subnets=ipset_to_subnet_list(st->networks);
1011     st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
1012     buffer_new(&st->icmp,ICMP_BUFSIZE);
1013     st->outcount=0;
1014     st->localcount=0;
1015
1016     add_hook(PHASE_SETUP,netlink_phase_hook,st);
1017     request_signal_notification(SIGUSR1, netlink_signal_handler, st);
1018
1019     /* If we're point-to-point then we return a CL_NETLINK directly,
1020        rather than a CL_NETLINK_OLD or pure closure (depending on
1021        compatibility).  This CL_NETLINK is for our one and only
1022        client.  Our cl.apply function is NULL. */
1023     if (st->ptp) {
1024         closure_t *cl;
1025         cl=netlink_inst_create(st,loc,dict);
1026         st->cl=*cl;
1027     }
1028     return netlink_dev_incoming;
1029 }
1030
1031 /* No connection to the kernel at all... */
1032
1033 struct null {
1034     struct netlink nl;
1035 };
1036
1037 static bool_t null_set_route(void *sst, struct netlink_client *routes)
1038 {
1039     struct null *st=sst;
1040
1041     if (routes->up!=routes->kup) {
1042         Message(M_INFO,"%s: setting routes for tunnel %s to state %s\n",
1043                 st->nl.name,routes->name,
1044                 routes->up?"up":"down");
1045         routes->kup=routes->up;
1046         return True;
1047     }
1048     return False;
1049 }
1050             
1051 static void null_deliver(void *sst, struct buffer_if *buf)
1052 {
1053     return;
1054 }
1055
1056 static list_t *null_apply(closure_t *self, struct cloc loc, dict_t *context,
1057                           list_t *args)
1058 {
1059     struct null *st;
1060     item_t *item;
1061     dict_t *dict;
1062
1063     st=safe_malloc(sizeof(*st),"null_apply");
1064
1065     item=list_elem(args,0);
1066     if (!item || item->type!=t_dict)
1067         cfgfatal(loc,"null-netlink","parameter must be a dictionary\n");
1068     
1069     dict=item->data.dict;
1070
1071     netlink_init(&st->nl,st,loc,dict,"null-netlink",null_set_route,
1072                  null_deliver);
1073
1074     return new_closure(&st->nl.cl);
1075 }
1076
1077 void netlink_module(dict_t *dict)
1078 {
1079     add_closure(dict,"null-netlink",null_apply);
1080 }