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