Import release 0.1.7
[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
042a8da9
SE
11/* XXX new feature: "point-to-point" mode. Instead of specifying a
12 secnet-address in the configuration dictionary, the user specifies
13 the address of the machine at the other end of the (one and only)
14 tunnel. We bypass all IP packet processing code. This mode is
15 useful for leafnodes like laptops, which don't require a secnet
16 router address. */
17
8689b3a9 18#include "secnet.h"
2fe58dfd 19#include "util.h"
7138d0c5 20#include "ipaddr.h"
9d3a4132 21#include "netlink.h"
042a8da9 22#include "process.h"
2fe58dfd 23
4efd681a
SE
24/* Generic IP checksum routine */
25static inline uint16_t ip_csum(uint8_t *iph,uint32_t count)
2fe58dfd 26{
4efd681a
SE
27 register uint32_t sum=0;
28
29 while (count>1) {
30 sum+=ntohs(*(uint16_t *)iph);
31 iph+=2;
32 count-=2;
33 }
34 if(count>0)
35 sum+=*(uint8_t *)iph;
36 while (sum>>16)
37 sum=(sum&0xffff)+(sum>>16);
38 return htons(~sum);
2fe58dfd
SE
39}
40
4efd681a
SE
41#ifdef i386
42/*
43 * This is a version of ip_compute_csum() optimized for IP headers,
44 * which always checksum on 4 octet boundaries.
45 *
46 * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
47 * Arnt Gulbrandsen.
48 */
49static inline uint16_t ip_fast_csum(uint8_t *iph, uint32_t ihl) {
50 uint32_t sum;
51
52 __asm__ __volatile__("
53 movl (%1), %0
54 subl $4, %2
55 jbe 2f
56 addl 4(%1), %0
57 adcl 8(%1), %0
58 adcl 12(%1), %0
591: adcl 16(%1), %0
60 lea 4(%1), %1
61 decl %2
62 jne 1b
63 adcl $0, %0
64 movl %0, %2
65 shrl $16, %0
66 addw %w2, %w0
67 adcl $0, %0
68 notl %0
692:
70 "
71 /* Since the input registers which are loaded with iph and ipl
72 are modified, we must also specify them as outputs, or gcc
73 will assume they contain their original values. */
74 : "=r" (sum), "=r" (iph), "=r" (ihl)
75 : "1" (iph), "2" (ihl));
76 return sum;
77}
78#else
79static inline uint16_t ip_fast_csum(uint8_t *iph, uint32_t ihl)
2fe58dfd 80{
4efd681a
SE
81 return ip_csum(iph,ihl*4);
82}
83#endif
84
85struct iphdr {
86#if defined (WORDS_BIGENDIAN)
87 uint8_t version:4,
88 ihl:4;
89#else
90 uint8_t ihl:4,
91 version:4;
92#endif
93 uint8_t tos;
94 uint16_t tot_len;
95 uint16_t id;
96 uint16_t frag_off;
97 uint8_t ttl;
98 uint8_t protocol;
99 uint16_t check;
100 uint32_t saddr;
101 uint32_t daddr;
102 /* The options start here. */
103};
104
105struct icmphdr {
106 struct iphdr iph;
107 uint8_t type;
108 uint8_t code;
109 uint16_t check;
110 union {
111 uint32_t unused;
112 struct {
113 uint8_t pointer;
114 uint8_t unused1;
115 uint16_t unused2;
116 } pprob;
117 uint32_t gwaddr;
118 struct {
119 uint16_t id;
120 uint16_t seq;
121 } echo;
122 } d;
123};
124
70dc107b
SE
125static void netlink_packet_deliver(struct netlink *st,
126 struct netlink_client *client,
127 struct buffer_if *buf);
4efd681a
SE
128
129static struct icmphdr *netlink_icmp_tmpl(struct netlink *st,
130 uint32_t dest,uint16_t len)
131{
132 struct icmphdr *h;
133
134 BUF_ALLOC(&st->icmp,"netlink_icmp_tmpl");
135 buffer_init(&st->icmp,st->max_start_pad);
136 h=buf_append(&st->icmp,sizeof(*h));
137
138 h->iph.version=4;
139 h->iph.ihl=5;
140 h->iph.tos=0;
141 h->iph.tot_len=htons(len+(h->iph.ihl*4)+8);
142 h->iph.id=0;
143 h->iph.frag_off=0;
144 h->iph.ttl=255;
145 h->iph.protocol=1;
146 h->iph.saddr=htonl(st->secnet_address);
147 h->iph.daddr=htonl(dest);
148 h->iph.check=0;
149 h->iph.check=ip_fast_csum((uint8_t *)&h->iph,h->iph.ihl);
150 h->check=0;
151 h->d.unused=0;
152
153 return h;
154}
155
156/* Fill in the ICMP checksum field correctly */
157static void netlink_icmp_csum(struct icmphdr *h)
158{
159 uint32_t len;
160
161 len=ntohs(h->iph.tot_len)-(4*h->iph.ihl);
162 h->check=0;
163 h->check=ip_csum(&h->type,len);
164}
165
166/* RFC1122:
167 * An ICMP error message MUST NOT be sent as the result of
168 * receiving:
169 *
170 * * an ICMP error message, or
171 *
172 * * a datagram destined to an IP broadcast or IP multicast
173 * address, or
174 *
175 * * a datagram sent as a link-layer broadcast, or
176 *
177 * * a non-initial fragment, or
178 *
179 * * a datagram whose source address does not define a single
180 * host -- e.g., a zero address, a loopback address, a
181 * broadcast address, a multicast address, or a Class E
182 * address.
183 */
184static bool_t netlink_icmp_may_reply(struct buffer_if *buf)
185{
186 struct iphdr *iph;
187 uint32_t source;
188
189 iph=(struct iphdr *)buf->start;
190 if (iph->protocol==1) return False; /* Overly-broad; we may reply to
191 eg. icmp echo-request */
192 /* How do we spot broadcast destination addresses? */
193 if (ntohs(iph->frag_off)&0x1fff) return False; /* Non-initial fragment */
194 source=ntohl(iph->saddr);
195 if (source==0) return False;
196 if ((source&0xff000000)==0x7f000000) return False;
197 /* How do we spot broadcast source addresses? */
198 if ((source&0xf0000000)==0xe0000000) return False; /* Multicast */
199 if ((source&0xf0000000)==0xf0000000) return False; /* Class E */
200 return True;
201}
202
203/* How much of the original IP packet do we include in its ICMP
204 response? The header plus up to 64 bits. */
205static uint16_t netlink_icmp_reply_len(struct buffer_if *buf)
206{
207 struct iphdr *iph=(struct iphdr *)buf->start;
208 uint16_t hlen,plen;
209
210 hlen=iph->ihl*4;
211 /* We include the first 8 bytes of the packet data, provided they exist */
212 hlen+=8;
213 plen=ntohs(iph->tot_len);
214 return (hlen>plen?plen:hlen);
215}
216
70dc107b
SE
217/* client indicates where the packet we're constructing a response to
218 comes from. NULL indicates the host. */
4efd681a 219static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf,
70dc107b 220 struct netlink_client *client,
4efd681a
SE
221 uint8_t type, uint8_t code)
222{
223 struct iphdr *iph=(struct iphdr *)buf->start;
224 struct icmphdr *h;
225 uint16_t len;
226
227 if (netlink_icmp_may_reply(buf)) {
228 len=netlink_icmp_reply_len(buf);
229 h=netlink_icmp_tmpl(st,ntohl(iph->saddr),len);
230 h->type=type; h->code=code;
231 memcpy(buf_append(&st->icmp,len),buf->start,len);
232 netlink_icmp_csum(h);
70dc107b 233 netlink_packet_deliver(st,NULL,&st->icmp);
4efd681a
SE
234 BUF_ASSERT_FREE(&st->icmp);
235 }
236}
237
238/*
239 * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the
240 * checksum.
241 *
242 * Is the datagram acceptable?
243 *
244 * 1. Length at least the size of an ip header
245 * 2. Version of 4
246 * 3. Checksums correctly.
247 * 4. Doesn't have a bogus length
248 */
249static bool_t netlink_check(struct netlink *st, struct buffer_if *buf)
250{
251 struct iphdr *iph=(struct iphdr *)buf->start;
252 uint32_t len;
253
9d3a4132
SE
254 if (iph->ihl < 5 || iph->version != 4) return False;
255 if (buf->size < iph->ihl*4) return False;
256 if (ip_fast_csum((uint8_t *)iph, iph->ihl)!=0) return False;
4efd681a
SE
257 len=ntohs(iph->tot_len);
258 /* There should be no padding */
9d3a4132 259 if (buf->size!=len || len<(iph->ihl<<2)) return False;
4efd681a
SE
260 /* XXX check that there's no source route specified */
261 return True;
262}
263
70dc107b
SE
264/* Deliver a packet. "client" points to the _origin_ of the packet, not
265 its destination. (May be used when sending ICMP response - avoid
266 asymmetric routing.) */
267static void netlink_packet_deliver(struct netlink *st,
268 struct netlink_client *client,
269 struct buffer_if *buf)
4efd681a
SE
270{
271 struct iphdr *iph=(struct iphdr *)buf->start;
272 uint32_t dest=ntohl(iph->daddr);
70dc107b
SE
273 uint32_t source=ntohl(iph->saddr);
274 uint32_t best_quality;
275 int best_match;
276 int i;
2fe58dfd 277
4efd681a 278 BUF_ASSERT_USED(buf);
2fe58dfd 279
4efd681a
SE
280 if (dest==st->secnet_address) {
281 Message(M_ERROR,"%s: trying to deliver a packet to myself!\n");
282 BUF_FREE(buf);
2fe58dfd
SE
283 return;
284 }
4efd681a 285
3454dce4
SE
286 /* XXX we're going to need an extra value 'allow_route' for the
287 source of the packet. It's always True for packets from the
288 host. For packets from tunnels, we consult the client
289 options. If !allow_route and the destination is a tunnel that
290 also doesn't allow routing, we must reject the packet with an
291 'administratively prohibited' or something similar ICMP. */
70dc107b
SE
292 if (!client) {
293 /* Origin of packet is host or secnet. Might be for a tunnel. */
294 best_quality=0;
295 best_match=-1;
296 for (i=0; i<st->n_routes; i++) {
9d3a4132 297 if (st->routes[i].up && subnet_match(&st->routes[i].net,dest)) {
70dc107b
SE
298 if (st->routes[i].c->link_quality>best_quality
299 || best_quality==0) {
300 best_quality=st->routes[i].c->link_quality;
301 best_match=i;
302 /* If quality isn't perfect we may wish to
303 consider kicking the tunnel with a 0-length
304 packet to prompt it to perform a key setup.
305 Then it'll eventually decide it's up or
306 down. */
307 /* If quality is perfect we don't need to search
308 any more. */
309 if (best_quality>=MAXIMUM_LINK_QUALITY) break;
310 }
311 }
312 }
313 if (best_match==-1) {
314 /* Not going down a tunnel. Might be for the host.
315 XXX think about this - only situation should be if we're
316 sending ICMP. */
317 if (source!=st->secnet_address) {
318 Message(M_ERROR,"netlink_packet_deliver: outgoing packet "
319 "from host that won't fit down any of our tunnels!\n");
9d3a4132
SE
320 /* XXX I think this could also occur if a soft tunnel just
321 went down, but still had packets queued in the kernel. */
70dc107b
SE
322 BUF_FREE(buf);
323 } else {
324 st->deliver_to_host(st->dst,NULL,buf);
325 BUF_ASSERT_FREE(buf);
326 }
327 } else {
328 if (best_quality>0) {
329 st->routes[best_match].c->deliver(
330 st->routes[best_match].c->dst,
331 st->routes[best_match].c, buf);
4efd681a
SE
332 BUF_ASSERT_FREE(buf);
333 } else {
334 /* Generate ICMP destination unreachable */
70dc107b 335 netlink_icmp_simple(st,buf,client,3,0); /* client==NULL */
4efd681a
SE
336 BUF_FREE(buf);
337 }
70dc107b
SE
338 }
339 } else { /* client is set */
340 /* We know the origin is a tunnel - packet must be for the host */
3454dce4
SE
341 /* XXX THIS IS NOT NECESSARILY TRUE, AND NEEDS FIXING */
342 /* THIS FUNCTION MUST JUST DELIVER THE PACKET: IT MUST ASSUME
343 THE PACKET HAS ALREADY BEEN CHECKED */
70dc107b
SE
344 if (subnet_matches_list(&st->networks,dest)) {
345 st->deliver_to_host(st->dst,NULL,buf);
346 BUF_ASSERT_FREE(buf);
347 } else {
348 Message(M_ERROR,"%s: packet from tunnel %s can't be delivered "
349 "to the host\n",st->name,client->name);
350 netlink_icmp_simple(st,buf,client,3,0);
351 BUF_FREE(buf);
2fe58dfd
SE
352 }
353 }
70dc107b 354 BUF_ASSERT_FREE(buf);
4efd681a
SE
355}
356
70dc107b
SE
357static void netlink_packet_forward(struct netlink *st,
358 struct netlink_client *client,
359 struct buffer_if *buf)
4efd681a
SE
360{
361 struct iphdr *iph=(struct iphdr *)buf->start;
362
363 BUF_ASSERT_USED(buf);
364
365 /* Packet has already been checked */
366 if (iph->ttl<=1) {
367 /* Generate ICMP time exceeded */
70dc107b 368 netlink_icmp_simple(st,buf,client,11,0);
4efd681a
SE
369 BUF_FREE(buf);
370 return;
371 }
372 iph->ttl--;
373 iph->check=0;
374 iph->check=ip_fast_csum((uint8_t *)iph,iph->ihl);
375
70dc107b 376 netlink_packet_deliver(st,client,buf);
4efd681a
SE
377 BUF_ASSERT_FREE(buf);
378}
379
9d3a4132 380/* Deal with packets addressed explicitly to us */
70dc107b
SE
381static void netlink_packet_local(struct netlink *st,
382 struct netlink_client *client,
383 struct buffer_if *buf)
4efd681a
SE
384{
385 struct icmphdr *h;
386
387 h=(struct icmphdr *)buf->start;
388
389 if ((ntohs(h->iph.frag_off)&0xbfff)!=0) {
9d3a4132
SE
390 Message(M_WARNING,"%s: fragmented packet addressed to secnet; "
391 "ignoring it\n",st->name);
4efd681a
SE
392 BUF_FREE(buf);
393 return;
394 }
395
396 if (h->iph.protocol==1) {
397 /* It's ICMP */
398 if (h->type==8 && h->code==0) {
399 /* ICMP echo-request. Special case: we re-use the buffer
400 to construct the reply. */
401 h->type=0;
402 h->iph.daddr=h->iph.saddr;
403 h->iph.saddr=htonl(st->secnet_address);
404 h->iph.ttl=255; /* Be nice and bump it up again... */
405 h->iph.check=0;
406 h->iph.check=ip_fast_csum((uint8_t *)h,h->iph.ihl);
407 netlink_icmp_csum(h);
70dc107b 408 netlink_packet_deliver(st,NULL,buf);
4efd681a
SE
409 return;
410 }
411 Message(M_WARNING,"%s: unknown incoming ICMP\n",st->name);
412 } else {
413 /* Send ICMP protocol unreachable */
70dc107b 414 netlink_icmp_simple(st,buf,client,3,2);
4efd681a
SE
415 BUF_FREE(buf);
416 return;
417 }
418
419 BUF_FREE(buf);
420}
421
9d3a4132
SE
422/* If cid==NULL packet is from host, otherwise cid specifies which tunnel
423 it came from. */
424static void netlink_incoming(void *sst, void *cid, struct buffer_if *buf)
4efd681a
SE
425{
426 struct netlink *st=sst;
9d3a4132 427 struct netlink_client *client=cid;
4efd681a
SE
428 uint32_t source,dest;
429 struct iphdr *iph;
430
431 BUF_ASSERT_USED(buf);
432 if (!netlink_check(st,buf)) {
9d3a4132
SE
433 Message(M_WARNING,"%s: bad IP packet from %s\n",
434 st->name,client?client->name:"host");
4efd681a
SE
435 BUF_FREE(buf);
436 return;
437 }
438 iph=(struct iphdr *)buf->start;
439
440 source=ntohl(iph->saddr);
441 dest=ntohl(iph->daddr);
442
9d3a4132
SE
443 /* Check source */
444 if (client) {
445 /* Check that the packet source is in 'nets' and its destination is
446 in st->networks */
447 if (!subnet_matches_list(client->networks,source)) {
448 string_t s,d;
449 s=ipaddr_to_string(source);
450 d=ipaddr_to_string(dest);
451 Message(M_WARNING,"%s: packet from tunnel %s with bad "
452 "source address (s=%s,d=%s)\n",st->name,client->name,s,d);
453 free(s); free(d);
454 BUF_FREE(buf);
455 return;
456 }
457 } else {
458 if (!subnet_matches_list(&st->networks,source)) {
459 string_t s,d;
460 s=ipaddr_to_string(source);
461 d=ipaddr_to_string(dest);
462 Message(M_WARNING,"%s: outgoing packet with bad source address "
463 "(s=%s,d=%s)\n",st->name,s,d);
464 free(s); free(d);
465 BUF_FREE(buf);
466 return;
467 }
4efd681a 468 }
9d3a4132
SE
469 /* (st->secnet_address needs checking before matching destination
470 addresses) */
2fe58dfd 471 if (dest==st->secnet_address) {
9d3a4132 472 netlink_packet_local(st,client,buf);
4efd681a 473 BUF_ASSERT_FREE(buf);
2fe58dfd
SE
474 return;
475 }
9d3a4132 476 if (client) {
3454dce4 477 /* Check for free routing */
9d3a4132
SE
478 if (!subnet_matches_list(&st->networks,dest)) {
479 string_t s,d;
480 s=ipaddr_to_string(source);
481 d=ipaddr_to_string(dest);
482 Message(M_WARNING,"%s: incoming packet from tunnel %s "
483 "with bad destination address "
484 "(s=%s,d=%s)\n",st->name,client->name,s,d);
485 free(s); free(d);
486 BUF_FREE(buf);
487 return;
488 }
2fe58dfd 489 }
70dc107b 490 netlink_packet_forward(st,client,buf);
4efd681a
SE
491 BUF_ASSERT_FREE(buf);
492}
493
9d3a4132 494static void netlink_set_softlinks(struct netlink *st, struct netlink_client *c,
042a8da9 495 bool_t up, uint32_t quality)
4efd681a 496{
9d3a4132 497 uint32_t i;
4efd681a 498
9d3a4132
SE
499 if (!st->routes) return; /* Table has not yet been created */
500 for (i=0; i<st->n_routes; i++) {
042a8da9
SE
501 if (st->routes[i].c==c) {
502 st->routes[i].quality=quality;
503 if (!st->routes[i].hard) {
504 st->routes[i].up=up;
505 st->set_route(st->dst,&st->routes[i]);
506 }
9d3a4132 507 }
4efd681a 508 }
4efd681a
SE
509}
510
70dc107b 511static void netlink_set_quality(void *sst, void *cid, uint32_t quality)
4efd681a 512{
9d3a4132 513 struct netlink *st=sst;
4efd681a
SE
514 struct netlink_client *c=cid;
515
70dc107b 516 c->link_quality=quality;
9d3a4132 517 if (c->link_quality==LINK_QUALITY_DOWN) {
042a8da9 518 netlink_set_softlinks(st,c,False,c->link_quality);
9d3a4132 519 } else {
042a8da9 520 netlink_set_softlinks(st,c,True,c->link_quality);
9d3a4132 521 }
4efd681a
SE
522}
523
524static void *netlink_regnets(void *sst, struct subnet_list *nets,
525 netlink_deliver_fn *deliver, void *dst,
526 uint32_t max_start_pad, uint32_t max_end_pad,
3454dce4 527 uint32_t options, string_t client_name)
4efd681a
SE
528{
529 struct netlink *st=sst;
530 struct netlink_client *c;
531
532 Message(M_DEBUG_CONFIG,"netlink_regnets: request for %d networks, "
533 "max_start_pad=%d, max_end_pad=%d\n",
534 nets->entries,max_start_pad,max_end_pad);
535
3454dce4 536 if ((options&NETLINK_OPTION_SOFTROUTE) && !st->set_route) {
9d3a4132
SE
537 Message(M_ERROR,"%s: this netlink device does not support "
538 "soft routes.\n");
539 return NULL;
540 }
541
3454dce4 542 if (options&NETLINK_OPTION_SOFTROUTE) {
9d3a4132 543 /* XXX for now we assume that soft routes require root privilege;
3454dce4 544 this may not always be true. The device driver can tell us. */
9d3a4132
SE
545 require_root_privileges=True;
546 require_root_privileges_explanation="netlink: soft routes";
547 }
548
9d3a4132
SE
549 /* Check that nets do not intersect st->exclude_remote_networks;
550 refuse to register if they do. */
baa06aeb
SE
551 if (subnet_lists_intersect(&st->exclude_remote_networks,nets)) {
552 Message(M_ERROR,"%s: site %s specifies networks that "
553 "intersect with the explicitly excluded remote networks\n",
554 st->name,client_name);
555 return False;
556 }
557
4efd681a
SE
558 c=safe_malloc(sizeof(*c),"netlink_regnets");
559 c->networks=nets;
560 c->deliver=deliver;
561 c->dst=dst;
562 c->name=client_name; /* XXX copy it? */
3454dce4 563 c->options=options;
70dc107b 564 c->link_quality=LINK_QUALITY_DOWN;
4efd681a
SE
565 c->next=st->clients;
566 st->clients=c;
567 if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
568 if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad;
70dc107b 569 st->n_routes+=nets->entries;
4efd681a
SE
570
571 return c;
572}
573
042a8da9 574static void netlink_dump_routes(struct netlink *st, bool_t requested)
9d3a4132
SE
575{
576 int i;
577 string_t net;
042a8da9 578 uint32_t c=M_INFO;
9d3a4132 579
042a8da9
SE
580 if (requested) c=M_WARNING;
581 Message(c,"%s: routing table:\n",st->name);
9d3a4132
SE
582 for (i=0; i<st->n_routes; i++) {
583 net=subnet_to_string(&st->routes[i].net);
042a8da9 584 Message(c,"%s -> tunnel %s (%s,%s route,%s,quality %d)\n",net,
3454dce4 585 st->routes[i].c->name,
9d3a4132 586 st->routes[i].hard?"hard":"soft",
3454dce4 587 st->routes[i].allow_route?"free":"restricted",
042a8da9
SE
588 st->routes[i].up?"up":"down",
589 st->routes[i].quality);
9d3a4132
SE
590 free(net);
591 }
042a8da9 592 Message(c,"%s/32 -> netlink \"%s\"\n",
9d3a4132
SE
593 ipaddr_to_string(st->secnet_address),st->name);
594 for (i=0; i<st->networks.entries; i++) {
595 net=subnet_to_string(&st->networks.list[i]);
042a8da9 596 Message(c,"%s -> host\n",net);
9d3a4132
SE
597 free(net);
598 }
599}
600
70dc107b
SE
601static int netlink_compare_route_specificity(const void *ap, const void *bp)
602{
603 const struct netlink_route *a=ap;
604 const struct netlink_route *b=bp;
605
606 if (a->net.len==b->net.len) return 0;
607 if (a->net.len<b->net.len) return 1;
608 return -1;
609}
610
611static void netlink_phase_hook(void *sst, uint32_t new_phase)
612{
613 struct netlink *st=sst;
614 struct netlink_client *c;
615 uint32_t i,j;
616
617 /* All the networks serviced by the various tunnels should now
618 * have been registered. We build a routing table by sorting the
619 * routes into most-specific-first order. */
620 st->routes=safe_malloc(st->n_routes*sizeof(*st->routes),
621 "netlink_phase_hook");
622 /* Fill the table */
623 i=0;
624 for (c=st->clients; c; c=c->next) {
625 for (j=0; j<c->networks->entries; j++) {
626 st->routes[i].net=c->networks->list[j];
627 st->routes[i].c=c;
3454dce4
SE
628 /* Hard routes are always up;
629 soft routes default to down */
630 st->routes[i].up=c->options&NETLINK_OPTION_SOFTROUTE?False:True;
9d3a4132 631 st->routes[i].kup=False;
3454dce4
SE
632 st->routes[i].hard=c->options&NETLINK_OPTION_SOFTROUTE?False:True;
633 st->routes[i].allow_route=c->options&NETLINK_OPTION_ALLOW_ROUTE?
634 True:False;
042a8da9 635 st->routes[i].quality=c->link_quality;
70dc107b
SE
636 i++;
637 }
638 }
639 /* ASSERT i==st->n_routes */
640 if (i!=st->n_routes) {
641 fatal("netlink: route count error: expected %d got %d\n",
642 st->n_routes,i);
643 }
644 /* Sort the table in descending order of specificity */
645 qsort(st->routes,st->n_routes,sizeof(*st->routes),
646 netlink_compare_route_specificity);
9d3a4132 647
042a8da9
SE
648 netlink_dump_routes(st,False);
649}
650
651static void netlink_signal_handler(void *sst, int signum)
652{
653 struct netlink *st=sst;
654 Message(M_INFO,"%s: route dump requested by SIGUSR1\n",st->name);
655 netlink_dump_routes(st,True);
70dc107b
SE
656}
657
9d3a4132
SE
658netlink_deliver_fn *netlink_init(struct netlink *st,
659 void *dst, struct cloc loc,
660 dict_t *dict, string_t description,
661 netlink_route_fn *set_route,
662 netlink_deliver_fn *to_host)
4efd681a
SE
663{
664 st->dst=dst;
665 st->cl.description=description;
666 st->cl.type=CL_NETLINK;
667 st->cl.apply=NULL;
668 st->cl.interface=&st->ops;
669 st->ops.st=st;
670 st->ops.regnets=netlink_regnets;
9d3a4132 671 st->ops.deliver=netlink_incoming;
70dc107b 672 st->ops.set_quality=netlink_set_quality;
4efd681a
SE
673 st->max_start_pad=0;
674 st->max_end_pad=0;
675 st->clients=NULL;
9d3a4132 676 st->set_route=set_route;
4efd681a
SE
677 st->deliver_to_host=to_host;
678
679 st->name=dict_read_string(dict,"name",False,"netlink",loc);
680 if (!st->name) st->name=description;
681 dict_read_subnet_list(dict, "networks", True, "netlink", loc,
682 &st->networks);
baa06aeb
SE
683 dict_read_subnet_list(dict, "exclude-remote-networks", False, "netlink",
684 loc, &st->exclude_remote_networks);
b2a56f7c
SE
685 /* secnet-address does not have to be in local-networks;
686 however, it should be advertised in the 'sites' file for the
baa06aeb 687 local site. */
4efd681a
SE
688 st->secnet_address=string_to_ipaddr(
689 dict_find_item(dict,"secnet-address", True, "netlink", loc),"netlink");
4efd681a
SE
690 st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
691 buffer_new(&st->icmp,ICMP_BUFSIZE);
70dc107b
SE
692 st->n_routes=0;
693 st->routes=NULL;
694
695 add_hook(PHASE_SETUP,netlink_phase_hook,st);
042a8da9 696 request_signal_notification(SIGUSR1, netlink_signal_handler, st);
4efd681a 697
9d3a4132 698 return netlink_incoming;
2fe58dfd
SE
699}
700
9d3a4132 701/* No connection to the kernel at all... */
2fe58dfd 702
9d3a4132 703struct null {
4efd681a 704 struct netlink nl;
4efd681a 705};
2fe58dfd 706
9d3a4132 707static bool_t null_set_route(void *sst, struct netlink_route *route)
4efd681a 708{
9d3a4132
SE
709 struct null *st=sst;
710 string_t t;
4efd681a 711
9d3a4132
SE
712 if (route->up!=route->kup) {
713 t=subnet_to_string(&route->net);
714 Message(M_INFO,"%s: setting route %s to state %s\n",st->nl.name,
715 t, route->up?"up":"down");
716 free(t);
717 route->kup=route->up;
718 return True;
2fe58dfd 719 }
9d3a4132 720 return False;
2fe58dfd 721}
9d3a4132 722
2fe58dfd
SE
723static void null_deliver(void *sst, void *cid, struct buffer_if *buf)
724{
725 return;
726}
727
728static list_t *null_apply(closure_t *self, struct cloc loc, dict_t *context,
729 list_t *args)
730{
731 struct null *st;
4efd681a
SE
732 item_t *item;
733 dict_t *dict;
2fe58dfd 734
4efd681a 735 st=safe_malloc(sizeof(*st),"null_apply");
2fe58dfd 736
4efd681a
SE
737 item=list_elem(args,0);
738 if (!item || item->type!=t_dict)
739 cfgfatal(loc,"null-netlink","parameter must be a dictionary\n");
740
741 dict=item->data.dict;
742
9d3a4132
SE
743 netlink_init(&st->nl,st,loc,dict,"null-netlink",null_set_route,
744 null_deliver);
4efd681a
SE
745
746 return new_closure(&st->nl.cl);
2fe58dfd
SE
747}
748
749init_module netlink_module;
750void netlink_module(dict_t *dict)
751{
4efd681a 752 add_closure(dict,"null-netlink",null_apply);
2fe58dfd 753}