Import release 0.1.11
[secnet] / netlink.c
CommitLineData
2fe58dfd
SE
1/* User-kernel network link */
2
baa06aeb
SE
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. */
2fe58dfd
SE
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
8689b3a9 11#include "secnet.h"
2fe58dfd 12#include "util.h"
7138d0c5 13#include "ipaddr.h"
9d3a4132 14#include "netlink.h"
042a8da9 15#include "process.h"
2fe58dfd 16
469fd1d9
SE
17#define OPT_SOFTROUTE 1
18#define OPT_ALLOWROUTE 2
19
4efd681a
SE
20/* Generic IP checksum routine */
21static inline uint16_t ip_csum(uint8_t *iph,uint32_t count)
2fe58dfd 22{
4efd681a
SE
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);
2fe58dfd
SE
35}
36
4efd681a
SE
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 */
45static 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
551: 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
652:
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
75static inline uint16_t ip_fast_csum(uint8_t *iph, uint32_t ihl)
2fe58dfd 76{
4efd681a
SE
77 return ip_csum(iph,ihl*4);
78}
79#endif
80
81struct 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
101struct 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
70dc107b
SE
121static void netlink_packet_deliver(struct netlink *st,
122 struct netlink_client *client,
123 struct buffer_if *buf);
4efd681a
SE
124
125static 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 */
153static 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 */
180static bool_t netlink_icmp_may_reply(struct buffer_if *buf)
181{
182 struct iphdr *iph;
8dea8d37 183 struct icmphdr *icmph;
4efd681a
SE
184 uint32_t source;
185
186 iph=(struct iphdr *)buf->start;
8dea8d37
SE
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 }
4efd681a
SE
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. */
209static 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
70dc107b
SE
221/* client indicates where the packet we're constructing a response to
222 comes from. NULL indicates the host. */
4efd681a 223static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf,
70dc107b 224 struct netlink_client *client,
4efd681a
SE
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);
70dc107b 237 netlink_packet_deliver(st,NULL,&st->icmp);
4efd681a
SE
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 */
253static 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
9d3a4132
SE
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;
4efd681a
SE
261 len=ntohs(iph->tot_len);
262 /* There should be no padding */
9d3a4132 263 if (buf->size!=len || len<(iph->ihl<<2)) return False;
4efd681a
SE
264 /* XXX check that there's no source route specified */
265 return True;
266}
267
469fd1d9
SE
268/* Deliver a packet. "client" is the _origin_ of the packet, not its
269destination. */
70dc107b
SE
270static void netlink_packet_deliver(struct netlink *st,
271 struct netlink_client *client,
272 struct buffer_if *buf)
4efd681a
SE
273{
274 struct iphdr *iph=(struct iphdr *)buf->start;
275 uint32_t dest=ntohl(iph->daddr);
70dc107b
SE
276 uint32_t source=ntohl(iph->saddr);
277 uint32_t best_quality;
469fd1d9
SE
278 bool_t allow_route=False;
279 bool_t found_allowed=False;
70dc107b
SE
280 int best_match;
281 int i;
2fe58dfd 282
4efd681a 283 BUF_ASSERT_USED(buf);
2fe58dfd 284
4efd681a 285 if (dest==st->secnet_address) {
469fd1d9 286 Message(M_ERR,"%s: trying to deliver a packet to myself!\n");
4efd681a 287 BUF_FREE(buf);
2fe58dfd
SE
288 return;
289 }
4efd681a 290
469fd1d9
SE
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++) {
794f2398 305 if (st->routes[i].up && subnet_match(st->routes[i].net,dest)) {
469fd1d9
SE
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;
70dc107b 314 }
469fd1d9
SE
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;
4efd681a 331 }
70dc107b 332 }
469fd1d9
SE
333 }
334 if (best_match==-1) {
335 /* The packet's not going down a tunnel. It might (ought to)
336 be for the host. */
794f2398 337 if (ipset_contains_addr(st->networks,dest)) {
469fd1d9
SE
338 st->deliver_to_host(st->dst,buf);
339 st->outcount++;
70dc107b
SE
340 BUF_ASSERT_FREE(buf);
341 } else {
469fd1d9
SE
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);
70dc107b
SE
348 netlink_icmp_simple(st,buf,client,3,0);
349 BUF_FREE(buf);
2fe58dfd 350 }
469fd1d9
SE
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 }
2fe58dfd 377 }
70dc107b 378 BUF_ASSERT_FREE(buf);
4efd681a
SE
379}
380
70dc107b
SE
381static void netlink_packet_forward(struct netlink *st,
382 struct netlink_client *client,
383 struct buffer_if *buf)
4efd681a
SE
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 */
70dc107b 392 netlink_icmp_simple(st,buf,client,11,0);
4efd681a
SE
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
70dc107b 400 netlink_packet_deliver(st,client,buf);
4efd681a
SE
401 BUF_ASSERT_FREE(buf);
402}
403
9d3a4132 404/* Deal with packets addressed explicitly to us */
70dc107b
SE
405static void netlink_packet_local(struct netlink *st,
406 struct netlink_client *client,
407 struct buffer_if *buf)
4efd681a
SE
408{
409 struct icmphdr *h;
410
469fd1d9
SE
411 st->localcount++;
412
4efd681a
SE
413 h=(struct icmphdr *)buf->start;
414
415 if ((ntohs(h->iph.frag_off)&0xbfff)!=0) {
9d3a4132
SE
416 Message(M_WARNING,"%s: fragmented packet addressed to secnet; "
417 "ignoring it\n",st->name);
4efd681a
SE
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);
70dc107b 434 netlink_packet_deliver(st,NULL,buf);
4efd681a
SE
435 return;
436 }
437 Message(M_WARNING,"%s: unknown incoming ICMP\n",st->name);
438 } else {
439 /* Send ICMP protocol unreachable */
70dc107b 440 netlink_icmp_simple(st,buf,client,3,2);
4efd681a
SE
441 BUF_FREE(buf);
442 return;
443 }
444
445 BUF_FREE(buf);
446}
447
9d3a4132
SE
448/* If cid==NULL packet is from host, otherwise cid specifies which tunnel
449 it came from. */
469fd1d9
SE
450static void netlink_incoming(struct netlink *st, struct netlink_client *client,
451 struct buffer_if *buf)
4efd681a 452{
4efd681a
SE
453 uint32_t source,dest;
454 struct iphdr *iph;
455
456 BUF_ASSERT_USED(buf);
457 if (!netlink_check(st,buf)) {
9d3a4132
SE
458 Message(M_WARNING,"%s: bad IP packet from %s\n",
459 st->name,client?client->name:"host");
4efd681a
SE
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
9d3a4132 468 /* Check source */
794f2398
SE
469 /* XXX consider generating ICMP if we're not point-to-point and we
470 don't like the packet */
9d3a4132 471 if (client) {
c6f79b17
SE
472 /* Check that the packet source is appropriate for the tunnel
473 it came down */
794f2398 474 if (!ipset_contains_addr(client->networks,source)) {
9d3a4132
SE
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 {
c6f79b17
SE
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 */
794f2398 488 if (!ipset_contains_addr(st->networks,source)) {
9d3a4132
SE
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 }
4efd681a 498 }
c6f79b17 499
794f2398
SE
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 */
c6f79b17
SE
505 if (st->ptp) {
506 if (client) {
469fd1d9 507 st->deliver_to_host(st->dst,buf);
c6f79b17 508 } else {
469fd1d9 509 st->clients->deliver(st->clients->dst,buf);
c6f79b17
SE
510 }
511 BUF_ASSERT_FREE(buf);
512 return;
513 }
514
9d3a4132
SE
515 /* (st->secnet_address needs checking before matching destination
516 addresses) */
2fe58dfd 517 if (dest==st->secnet_address) {
9d3a4132 518 netlink_packet_local(st,client,buf);
4efd681a 519 BUF_ASSERT_FREE(buf);
2fe58dfd
SE
520 return;
521 }
70dc107b 522 netlink_packet_forward(st,client,buf);
4efd681a
SE
523 BUF_ASSERT_FREE(buf);
524}
525
469fd1d9
SE
526static 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
534static 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
9d3a4132 541static void netlink_set_softlinks(struct netlink *st, struct netlink_client *c,
042a8da9 542 bool_t up, uint32_t quality)
4efd681a 543{
9d3a4132 544 uint32_t i;
4efd681a 545
9d3a4132
SE
546 if (!st->routes) return; /* Table has not yet been created */
547 for (i=0; i<st->n_routes; i++) {
042a8da9
SE
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 }
9d3a4132 554 }
4efd681a 555 }
4efd681a
SE
556}
557
469fd1d9 558static void netlink_set_quality(void *sst, uint32_t quality)
4efd681a 559{
469fd1d9
SE
560 struct netlink_client *c=sst;
561 struct netlink *st=c->nst;
4efd681a 562
70dc107b 563 c->link_quality=quality;
9d3a4132 564 if (c->link_quality==LINK_QUALITY_DOWN) {
042a8da9 565 netlink_set_softlinks(st,c,False,c->link_quality);
9d3a4132 566 } else {
042a8da9 567 netlink_set_softlinks(st,c,True,c->link_quality);
9d3a4132 568 }
4efd681a
SE
569}
570
042a8da9 571static void netlink_dump_routes(struct netlink *st, bool_t requested)
9d3a4132
SE
572{
573 int i;
574 string_t net;
042a8da9 575 uint32_t c=M_INFO;
9d3a4132 576
042a8da9 577 if (requested) c=M_WARNING;
469fd1d9
SE
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);
9d3a4132 582 free(net);
469fd1d9 583 for (i=0; i<st->n_routes; i++) {
794f2398 584 net=subnet_to_string(st->routes[i].net);
469fd1d9
SE
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++) {
794f2398 592 net=subnet_to_string(st->routes[i].net);
469fd1d9
SE
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);
9d3a4132 605 free(net);
794f2398
SE
606 for (i=0; i<st->subnets->entries; i++) {
607 net=subnet_to_string(st->subnets->list[i]);
608 Message(c,"%s ",net);
469fd1d9
SE
609 free(net);
610 }
794f2398
SE
611 if (i>0)
612 Message(c,"-> host (use %d)\n",st->outcount);
9d3a4132
SE
613 }
614}
615
70dc107b
SE
616static 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
626static 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) {
794f2398
SE
640 for (j=0; j<c->subnets->entries; j++) {
641 st->routes[i].net=c->subnets->list[j];
70dc107b 642 st->routes[i].c=c;
3454dce4 643 /* Hard routes are always up;
469fd1d9
SE
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;
9d3a4132 649 st->routes[i].kup=False;
469fd1d9
SE
650 st->routes[i].hard=c->options&OPT_SOFTROUTE?False:True;
651 st->routes[i].allow_route=c->options&OPT_ALLOWROUTE?
3454dce4 652 True:False;
042a8da9 653 st->routes[i].quality=c->link_quality;
469fd1d9 654 st->routes[i].outcount=0;
70dc107b
SE
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);
9d3a4132 666
042a8da9
SE
667 netlink_dump_routes(st,False);
668}
669
670static 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);
70dc107b
SE
675}
676
794f2398
SE
677static 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
686static 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
469fd1d9
SE
698static 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
711static 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. */
721static 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;
794f2398 726 struct ipset *networks;
469fd1d9 727 uint32_t options;
794f2398 728 list_t *l;
469fd1d9
SE
729
730 name=dict_read_string(dict, "name", True, st->name, loc);
731
794f2398
SE
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");
469fd1d9
SE
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
794f2398
SE
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");
469fd1d9
SE
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;
794f2398
SE
773 c->ops.output_config=netlink_inst_output_config;
774 c->ops.check_config=netlink_inst_check_config;
469fd1d9
SE
775 c->nst=st;
776
777 c->networks=networks;
794f2398 778 c->subnets=ipset_to_subnet_list(networks);
469fd1d9
SE
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;
794f2398 786 st->n_routes+=c->subnets->entries;
469fd1d9
SE
787
788 return &c->cl;
789}
790
791static 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
469fd1d9
SE
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
9d3a4132
SE
811netlink_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)
4efd681a 816{
c6f79b17 817 item_t *sa, *ptpa;
794f2398 818 list_t *l;
c6f79b17 819
4efd681a
SE
820 st->dst=dst;
821 st->cl.description=description;
469fd1d9
SE
822 st->cl.type=CL_PURE;
823 st->cl.apply=netlink_inst_apply;
824 st->cl.interface=st;
4efd681a
SE
825 st->max_start_pad=0;
826 st->max_end_pad=0;
827 st->clients=NULL;
9d3a4132 828 st->set_route=set_route;
4efd681a
SE
829 st->deliver_to_host=to_host;
830
794f2398 831 st->name=dict_read_string(dict,"name",False,description,loc);
4efd681a 832 if (!st->name) st->name=description;
794f2398
SE
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
c6f79b17 852 sa=dict_find_item(dict,"secnet-address",False,"netlink",loc);
469fd1d9 853 ptpa=dict_find_item(dict,"ptp-address",False,"netlink",loc);
c6f79b17
SE
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) {
794f2398 863 st->secnet_address=string_item_to_ipaddr(sa,"netlink");
c6f79b17
SE
864 st->ptp=False;
865 } else {
794f2398 866 st->secnet_address=string_item_to_ipaddr(ptpa,"netlink");
c6f79b17
SE
867 st->ptp=True;
868 }
794f2398
SE
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);
4efd681a
SE
873 st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
874 buffer_new(&st->icmp,ICMP_BUFSIZE);
70dc107b
SE
875 st->n_routes=0;
876 st->routes=NULL;
469fd1d9
SE
877 st->outcount=0;
878 st->localcount=0;
70dc107b
SE
879
880 add_hook(PHASE_SETUP,netlink_phase_hook,st);
042a8da9 881 request_signal_notification(SIGUSR1, netlink_signal_handler, st);
4efd681a 882
469fd1d9
SE
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;
2fe58dfd
SE
893}
894
9d3a4132 895/* No connection to the kernel at all... */
2fe58dfd 896
9d3a4132 897struct null {
4efd681a 898 struct netlink nl;
4efd681a 899};
2fe58dfd 900
9d3a4132 901static bool_t null_set_route(void *sst, struct netlink_route *route)
4efd681a 902{
9d3a4132
SE
903 struct null *st=sst;
904 string_t t;
4efd681a 905
9d3a4132 906 if (route->up!=route->kup) {
794f2398 907 t=subnet_to_string(route->net);
9d3a4132
SE
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;
2fe58dfd 913 }
9d3a4132 914 return False;
2fe58dfd 915}
9d3a4132 916
469fd1d9 917static void null_deliver(void *sst, struct buffer_if *buf)
2fe58dfd
SE
918{
919 return;
920}
921
922static list_t *null_apply(closure_t *self, struct cloc loc, dict_t *context,
923 list_t *args)
924{
925 struct null *st;
4efd681a
SE
926 item_t *item;
927 dict_t *dict;
2fe58dfd 928
4efd681a 929 st=safe_malloc(sizeof(*st),"null_apply");
2fe58dfd 930
4efd681a
SE
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
9d3a4132
SE
937 netlink_init(&st->nl,st,loc,dict,"null-netlink",null_set_route,
938 null_deliver);
4efd681a
SE
939
940 return new_closure(&st->nl.cl);
2fe58dfd
SE
941}
942
943init_module netlink_module;
944void netlink_module(dict_t *dict)
945{
4efd681a 946 add_closure(dict,"null-netlink",null_apply);
2fe58dfd 947}