Annotation of embedaddon/mpd/src/iface.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * iface.c
4: *
5: * Written by Archie Cobbs <archie@freebsd.org>
6: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
7: * See ``COPYRIGHT.whistle''
8: *
9: * TCP MSSFIX code copyright (c) 2000 Ruslan Ermilov
10: * TCP MSSFIX contributed by Sergey Korolew <dsATbittu.org.ru>
11: *
12: */
13:
14: #include "ppp.h"
15: #include "iface.h"
16: #include "ipcp.h"
17: #include "auth.h"
18: #include "ngfunc.h"
19: #include "netgraph.h"
20: #include "util.h"
21:
22: #include <sys/sockio.h>
23: #include <sys/sysctl.h>
24: #include <net/if.h>
25: #include <net/if_types.h>
26: #include <net/if_dl.h>
27: #include <net/if_var.h>
28: #include <net/route.h>
29: #include <netinet/in_systm.h>
30: #include <netinet/in.h>
31: #include <netinet/in_var.h>
32: #include <netinet/if_ether.h>
33: #include <netinet6/nd6.h>
34: #include <netgraph/ng_message.h>
35: #include <netgraph/ng_iface.h>
36: #ifdef USE_NG_BPF
37: #include <netgraph/ng_bpf.h>
38: #endif
39: #include <netgraph/ng_tee.h>
40: #include <netgraph/ng_ksocket.h>
41: #include <netinet/ip_icmp.h>
42: #include <netinet/tcp.h>
43: #include <netinet/udp.h>
44: #ifdef USE_NG_TCPMSS
45: #include <netgraph/ng_tcpmss.h>
46: #endif
47: #ifdef USE_NG_IPACCT
48: #include <netgraph/ng_ipacct.h>
49: #undef r_ip_p /* XXX:DIRTY CONFLICT! */
50: #endif
51: #ifdef USE_NG_NETFLOW
52: #include <netgraph/netflow/ng_netflow.h>
53: #endif
54: #ifdef USE_NG_CAR
55: #include <netgraph/ng_car.h>
56: #endif
57:
58: #ifdef USE_NG_BPF
59: #include <pcap.h>
60: #endif
61:
62: /*
63: * DEFINITIONS
64: */
65:
66: /* Set menu options */
67:
68: enum {
69: SET_IDLE,
70: SET_SESSION,
71: SET_ADDRS,
72: SET_ROUTE,
73: SET_MTU,
74: SET_NAME,
75: #ifdef SIOCSIFDESCR
76: SET_DESCR,
77: #endif
78: #ifdef SIOCAIFGROUP
79: SET_GROUP,
80: #endif
81: SET_UP_SCRIPT,
82: SET_DOWN_SCRIPT,
83: SET_ENABLE,
84: SET_DISABLE
85: };
86:
87: /*
88: * INTERNAL FUNCTIONS
89: */
90:
91: static int IfaceNgIpInit(Bund b, int ready);
92: static void IfaceNgIpShutdown(Bund b);
93: static int IfaceNgIpv6Init(Bund b, int ready);
94: static void IfaceNgIpv6Shutdown(Bund b);
95:
96: #ifdef USE_NG_NETFLOW
97: static int IfaceInitNetflow(Bund b, char *path, char *hook, char in, char out);
98: static int IfaceSetupNetflow(Bund b, char in, char out);
99: static void IfaceShutdownNetflow(Bund b, char in, char out);
100: #endif
101:
102: #ifdef USE_NG_IPACCT
103: static int IfaceInitIpacct(Bund b, char *path, char *hook);
104: static void IfaceShutdownIpacct(Bund b);
105: #endif
106:
107: #ifdef USE_NG_NAT
108: static int IfaceInitNAT(Bund b, char *path, char *hook);
109: static int IfaceSetupNAT(Bund b);
110: static void IfaceShutdownNAT(Bund b);
111: #endif
112:
113: static int IfaceInitTee(Bund b, char *path, char *hook, int v6);
114: static void IfaceShutdownTee(Bund b, int v6);
115:
116: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
117: static int IfaceInitMSS(Bund b, char *path, char *hook);
118: static void IfaceSetupMSS(Bund b, uint16_t maxMSS);
119: static void IfaceShutdownMSS(Bund b);
120: #endif
121:
122: #ifdef USE_NG_BPF
123: static int IfaceInitLimits(Bund b, char *path, char *hook);
124: static void IfaceSetupLimits(Bund b);
125: static void IfaceShutdownLimits(Bund b);
126: #endif
127:
128: static int IfaceSetCommand(Context ctx, int ac, char *av[], void *arg);
129: static void IfaceSessionTimeout(void *arg);
130: static void IfaceIdleTimeout(void *arg);
131:
132: static void IfaceCacheSend(Bund b);
133: static void IfaceCachePkt(Bund b, int proto, Mbuf pkt);
134: static int IfaceIsDemand(int proto, Mbuf pkt);
135:
136: #ifdef USE_IPFW
137: static int IfaceAllocACL (struct acl_pool ***ap, int start, char * ifname, int number);
138: static int IfaceFindACL (struct acl_pool *ap, char * ifname, int number);
139: static char * IFaceParseACL (char * src, char * ifname);
140: #endif
141:
142: static int IfaceSetName(Bund b, const char * ifname);
143: #ifdef SIOCSIFDESCR
144: static int IfaceSetDescr(Bund b, const char * ifdescr);
145: #endif
146: #ifdef SIOCAIFGROUP
147: static int IfaceAddGroup(Bund b, const char * ifgroup);
148: static int IfaceDelGroup(Bund b, const char * ifgroup);
149: #endif
150: /*
151: * GLOBAL VARIABLES
152: */
153:
154: const struct cmdtab IfaceSetCmds[] = {
155: { "addrs {self} {peer}", "Set interface addresses",
156: IfaceSetCommand, NULL, 2, (void *) SET_ADDRS },
157: { "route {dest}[/{width}]", "Add IP route",
158: IfaceSetCommand, NULL, 2, (void *) SET_ROUTE },
159: { "mtu {size}", "Set max allowed interface MTU",
160: IfaceSetCommand, NULL, 2, (void *) SET_MTU },
161: { "name [{name}]", "Set interface name",
162: IfaceSetCommand, NULL, 2, (void *) SET_NAME },
163: #ifdef SIOCSIFDESCR
164: { "description [{descr}]", "Set interface description",
165: IfaceSetCommand, NULL, 2, (void *) SET_DESCR },
166: #endif
167: #ifdef SIOCAIFGROUP
168: { "group [{group}]", "Set interface group",
169: IfaceSetCommand, NULL, 2, (void *) SET_GROUP },
170: #endif
171: { "up-script [{progname}]", "Interface up script",
172: IfaceSetCommand, NULL, 2, (void *) SET_UP_SCRIPT },
173: { "down-script [{progname}]", "Interface down script",
174: IfaceSetCommand, NULL, 2, (void *) SET_DOWN_SCRIPT },
175: #ifdef USE_NG_BPF
176: { "idle {seconds}", "Idle timeout",
177: IfaceSetCommand, NULL, 2, (void *) SET_IDLE },
178: #endif
179: { "session {seconds}", "Session timeout",
180: IfaceSetCommand, NULL, 2, (void *) SET_SESSION },
181: { "enable [opt ...]", "Enable option",
182: IfaceSetCommand, NULL, 2, (void *) SET_ENABLE },
183: { "disable [opt ...]", "Disable option",
184: IfaceSetCommand, NULL, 2, (void *) SET_DISABLE },
185: { NULL },
186: };
187:
188: /*
189: * INTERNAL VARIABLES
190: */
191:
192: static const struct confinfo gConfList[] = {
193: { 0, IFACE_CONF_ONDEMAND, "on-demand" },
194: { 0, IFACE_CONF_PROXY, "proxy-arp" },
195: #ifdef USE_NG_TCPMSS
196: { 0, IFACE_CONF_TCPMSSFIX, "tcpmssfix" },
197: #endif
198: { 0, IFACE_CONF_TEE, "tee" },
199: #ifdef USE_NG_NAT
200: { 0, IFACE_CONF_NAT, "nat" },
201: #endif
202: #ifdef USE_NG_NETFLOW
203: { 0, IFACE_CONF_NETFLOW_IN, "netflow-in" },
204: { 0, IFACE_CONF_NETFLOW_OUT, "netflow-out" },
205: #ifdef NG_NETFLOW_CONF_ONCE
206: { 0, IFACE_CONF_NETFLOW_ONCE, "netflow-once" },
207: #endif
208: #endif
209: #ifdef USE_NG_IPACCT
210: { 0, IFACE_CONF_IPACCT, "ipacct" },
211: #endif
212: { 0, 0, NULL },
213: };
214:
215: #ifdef USE_IPFW
216: struct acl_pool * rule_pool = NULL; /* Pointer to the first element in the list of rules */
217: struct acl_pool * pipe_pool = NULL; /* Pointer to the first element in the list of pipes */
218: struct acl_pool * queue_pool = NULL; /* Pointer to the first element in the list of queues */
219: struct acl_pool * table_pool = NULL; /* Pointer to the first element in the list of tables */
220: int rule_pool_start = 10000; /* Initial number of ipfw rules pool */
221: int pipe_pool_start = 10000; /* Initial number of ipfw dummynet pipe pool */
222: int queue_pool_start = 10000; /* Initial number of ipfw dummynet queue pool */
223: int table_pool_start = 32; /* Initial number of ipfw tables pool */
224: #endif
225:
226: #ifdef USE_NG_BPF
227: /* A BPF filter that matches TCP SYN packets */
228: static const struct bpf_insn gTCPSYNProg[] = {
229: /*00*/ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 9), /* A <- IP protocol */
230: /*01*/ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_TCP, 0, 6), /* !TCP => 8 */
231: /*02*/ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 6), /* A <- fragmentation offset */
232: /*03*/ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x1fff, 4, 0), /* fragment => 8 */
233: /*04*/ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 0), /* X <- header len */
234: /*05*/ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 13), /* A <- TCP flags */
235: /*06*/ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, TH_SYN, 0, 1), /* !TH_SYN => 8 */
236: /*07*/ BPF_STMT(BPF_RET+BPF_K, (u_int)-1), /* accept packet */
237: /*08*/ BPF_STMT(BPF_RET+BPF_K, 0), /* reject packet */
238: };
239:
240: #define TCPSYN_PROG_LEN (sizeof(gTCPSYNProg) / sizeof(*gTCPSYNProg))
241:
242: /* A BPF filter that matches nothing */
243: static const struct bpf_insn gNoMatchProg[] = {
244: BPF_STMT(BPF_RET+BPF_K, 0)
245: };
246:
247: #define NOMATCH_PROG_LEN (sizeof(gNoMatchProg) / sizeof(*gNoMatchProg))
248:
249: /* A BPF filter that matches everything */
250: static const struct bpf_insn gMatchProg[] = {
251: BPF_STMT(BPF_RET+BPF_K, (u_int)-1)
252: };
253:
254: #define MATCH_PROG_LEN (sizeof(gMatchProg) / sizeof(*gMatchProg))
255: #endif /* USE_NG_BPF */
256:
257: #define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
258: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
259: static const struct in6_addr in6mask128 = IN6MASK128;
260:
261:
262: /*
263: * IfaceInit()
264: */
265:
266: void
267: IfaceInit(Bund b)
268: {
269: IfaceState const iface = &b->iface;
270:
271: /* Default configuration */
272: iface->mtu = NG_IFACE_MTU_DEFAULT;
273: iface->max_mtu = NG_IFACE_MTU_DEFAULT;
274: #ifdef SIOCSIFDESCR
275: iface->ifdescr = NULL;
276: iface->conf.ifdescr = NULL;
277: #endif
278: Disable(&iface->options, IFACE_CONF_ONDEMAND);
279: Disable(&iface->options, IFACE_CONF_PROXY);
280: Disable(&iface->options, IFACE_CONF_TCPMSSFIX);
281: #ifdef USE_NG_NAT
282: NatInit(b);
283: #endif
284: #ifdef USE_NG_BPF
285: SLIST_INIT(&iface->ss[0]);
286: SLIST_INIT(&iface->ss[1]);
287: #endif
288: }
289:
290: /*
291: * IfaceInst()
292: */
293:
294: void
295: IfaceInst(Bund b, Bund bt)
296: {
297: IfaceState const iface = &b->iface;
298:
299: memcpy(iface, &bt->iface, sizeof(*iface));
300:
301: /* Copy interface name from template config to current */
302: if (bt->iface.conf.ifname[0] != 0 && b->tmpl == 0) {
303: snprintf(iface->conf.ifname, sizeof(iface->conf.ifname), "%s%d",
304: bt->iface.conf.ifname, b->id);
305: Log(LG_IFACE2, ("[%s] IFACE: Set conf.ifname to ", iface->conf.ifname));
306: }
307: }
308:
309: /*
310: * IfaceDestroy()
311: */
312:
313: void
314: IfaceDestroy(Bund b)
315: {
316: #ifdef SIOCSIFDESCR
317: IfaceState const iface = &b->iface;
318:
319: if (iface->conf.ifdescr != NULL)
320: Freee(iface->conf.ifdescr);
321: #endif
322: }
323:
324: /*
325: * IfaceOpen()
326: *
327: * Open the interface layer
328: */
329:
330: void
331: IfaceOpen(Bund b)
332: {
333: IfaceState const iface = &b->iface;
334:
335: Log(LG_IFACE, ("[%s] IFACE: Open event", b->name));
336:
337: /* Open is useless without on-demand. */
338: if (!Enabled(&iface->options, IFACE_CONF_ONDEMAND)) {
339: Log(LG_ERR, ("[%s] 'open iface' is useless without on-demand enabled", b->name));
340: return;
341: }
342:
343: /* If interface is already open do nothing */
344: if (iface->open)
345: return;
346: iface->open = TRUE;
347:
348: /* If on-demand, bring up system interface immediately and start
349: listening for outgoing packets. The next outgoing packet will
350: cause us to open the lower layer(s) */
351: BundNcpsJoin(b, NCP_NONE);
352: }
353:
354: /*
355: * IfaceClose()
356: *
357: * Close the interface layer
358: */
359:
360: void
361: IfaceClose(Bund b)
362: {
363: IfaceState const iface = &b->iface;
364:
365: Log(LG_IFACE, ("[%s] IFACE: Close event", b->name));
366:
367: /* If interface is already closed do nothing */
368: if (!iface->open)
369: return;
370: iface->open = FALSE;
371:
372: /* If there was on-demand, tell that it is not needed anymore */
373: BundNcpsLeave(b, NCP_NONE);
374: }
375:
376: /*
377: * IfaceOpenCmd()
378: *
379: * Open the interface layer
380: */
381:
382: int
383: IfaceOpenCmd(Context ctx)
384: {
385: if (ctx->bund->tmpl)
386: Error("impossible to open template");
387: IfaceOpen(ctx->bund);
388: return (0);
389: }
390:
391: /*
392: * IfaceCloseCmd()
393: *
394: * Close the interface layer
395: */
396:
397: int
398: IfaceCloseCmd(Context ctx)
399: {
400: if (ctx->bund->tmpl)
401: Error("impossible to close template");
402: IfaceClose(ctx->bund);
403: return (0);
404: }
405:
406: /*
407: * IfaceUp()
408: *
409: * Our underlying PPP bundle is ready for traffic.
410: * We may signal that the interface is in DoD with the IFF_LINK0 flag.
411: */
412:
413: void
414: IfaceUp(Bund b, int ready)
415: {
416: IfaceState const iface = &b->iface;
417: int session_timeout = 0, idle_timeout = 0;
418: #ifdef USE_IPFW
419: struct acl *acls, *acl;
420: char *buf;
421: struct acl_pool **poollast;
422: int poollaststart;
423: int prev_number;
424: int prev_real_number;
425: #endif
426:
427: Log(LG_IFACE, ("[%s] IFACE: Up event", b->name));
428: iface->last_up = time(NULL);
429:
430: if (ready) {
431:
432: /* Start Session timer */
433: if (b->params.session_timeout > 0) {
434: session_timeout = b->params.session_timeout;
435: } else if (iface->session_timeout > 0) {
436: session_timeout = iface->session_timeout;
437: }
438:
439: if (session_timeout > 0) {
440: Log(LG_IFACE2, ("[%s] IFACE: session-timeout: %d seconds",
441: b->name, session_timeout));
442: if (session_timeout > INT_MAX / 1100) {
443: session_timeout = INT_MAX / 1100;
444: Log(LG_ERR, ("[%s] IFACE: session-timeout limited to %d seconds",
445: b->name, session_timeout));
446: }
447: TimerInit(&iface->sessionTimer, "IfaceSession",
448: session_timeout * SECONDS, IfaceSessionTimeout, b);
449: TimerStart(&iface->sessionTimer);
450: }
451:
452: /* Start idle timer */
453: if (b->params.idle_timeout > 0) {
454: idle_timeout = b->params.idle_timeout;
455: } else if (iface->idle_timeout > 0) {
456: idle_timeout = iface->idle_timeout;
457: }
458:
459: if (idle_timeout > 0) {
460: Log(LG_IFACE2, ("[%s] IFACE: idle-timeout: %d seconds",
461: b->name, idle_timeout));
462: if (idle_timeout > INT_MAX / 1100 * IFACE_IDLE_SPLIT) {
463: idle_timeout = INT_MAX / 1100 * IFACE_IDLE_SPLIT;
464: Log(LG_ERR, ("[%s] IFACE: idle-timeout limited to %d seconds",
465: b->name, idle_timeout));
466: }
467: TimerInit(&iface->idleTimer, "IfaceIdle",
468: idle_timeout * SECONDS / IFACE_IDLE_SPLIT, IfaceIdleTimeout, b);
469: TimerStart(&iface->idleTimer);
470: iface->traffic[1] = TRUE;
471: iface->traffic[0] = FALSE;
472:
473: /* Reset statistics */
474: memset(&iface->idleStats, 0, sizeof(iface->idleStats));
475: }
476:
477: /* Update interface name and description */
478: if (b->params.ifname[0] != 0) {
479: if (IfaceSetName(b, b->params.ifname) != -1)
480: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Rename interface %s to %s",
481: b->name, iface->ngname, b->params.ifname));
482: } else if (iface->conf.ifname[0] != 0) {
483: if (IfaceSetName(b, iface->conf.ifname) != -1)
484: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Rename interface %s to %s",
485: b->name, iface->ngname, iface->conf.ifname));
486: }
487: #ifdef SIOCSIFDESCR
488: if (b->params.ifdescr != NULL) {
489: if (IfaceSetDescr(b, b->params.ifdescr) != -1) {
490: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add description \"%s\"",
491: b->name, b->params.ifdescr));
492: iface->ifdescr = b->params.ifdescr;
493: }
494: }
495: #endif
496: #ifdef SIOCAIFGROUP
497: if (iface->conf.ifgroup[0] != 0) {
498: if (IfaceAddGroup(b, iface->conf.ifgroup) != -1)
499: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add group %s to %s",
500: b->name, iface->conf.ifgroup, iface->ngname));
501: }
502: if (b->params.ifgroup[0] != 0) {
503: if (IfaceAddGroup(b, b->params.ifgroup) != -1)
504: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add group %s to %s",
505: b->name, b->params.ifgroup, iface->ngname));
506: }
507: #endif
508: #ifdef USE_IPFW
509: /* Allocate ACLs */
510: acls = b->params.acl_pipe;
511: poollast = &pipe_pool;
512: poollaststart = pipe_pool_start;
513: while (acls != NULL) {
514: acls->real_number = IfaceAllocACL(&poollast, poollaststart, iface->ifname, acls->number);
515: poollaststart = acls->real_number;
516: acls = acls->next;
517: };
518: acls = b->params.acl_queue;
519: poollast = &queue_pool;
520: poollaststart = queue_pool_start;
521: while (acls != NULL) {
522: acls->real_number = IfaceAllocACL(&poollast, poollaststart, iface->ifname, acls->number);
523: poollaststart = acls->real_number;
524: acls = acls->next;
525: };
526: prev_number = -1;
527: prev_real_number = -1;
528: acls = b->params.acl_table;
529: poollast = &table_pool;
530: poollaststart = table_pool_start;
531: while (acls != NULL) {
532: if (acls->real_number == 0) {
533: if (acls->number == prev_number) { /* ACL list is presorted so we need not allocate if equal */
534: acls->real_number = prev_real_number;
535: } else {
536: acls->real_number = IfaceAllocACL(&poollast, poollaststart, iface->ifname, acls->number);
537: poollaststart = acls->real_number;
538: prev_number = acls->number;
539: prev_real_number = acls->real_number;
540: }
541: }
542: acls = acls->next;
543: };
544: acls = b->params.acl_rule;
545: poollast = &rule_pool;
546: poollaststart = rule_pool_start;
547: while (acls != NULL) {
548: acls->real_number = IfaceAllocACL(&poollast, poollaststart, iface->ifname, acls->number);
549: poollaststart = acls->real_number;
550: acls = acls->next;
551: };
552:
553: /* Set ACLs */
554: acls = b->params.acl_pipe;
555: while (acls != NULL) {
556: ExecCmd(LG_IFACE2, b->name, "%s pipe %d config %s", PATH_IPFW, acls->real_number, acls->rule);
557: acls = acls->next;
558: }
559: acls = b->params.acl_queue;
560: while (acls != NULL) {
561: buf = IFaceParseACL(acls->rule,iface->ifname);
562: ExecCmd(LG_IFACE2, b->name, "%s queue %d config %s", PATH_IPFW, acls->real_number, buf);
563: Freee(buf);
564: acls = acls->next;
565: }
566: acls = b->params.acl_table;
567: while (acls != NULL) {
568: acl = Mdup(MB_IFACE, acls, sizeof(struct acl) + strlen(acls->rule));
569: acl->next = iface->tables;
570: iface->tables = acl;
571: ExecCmd(LG_IFACE2, b->name, "%s table %d add %s", PATH_IPFW, acls->real_number, acls->rule);
572: acls = acls->next;
573: };
574: acls = b->params.acl_rule;
575: while (acls != NULL) {
576: buf = IFaceParseACL(acls->rule, iface->ifname);
577: ExecCmd(LG_IFACE2, b->name, "%s add %d %s via %s", PATH_IPFW, acls->real_number, buf, iface->ifname);
578: Freee(buf);
579: acls = acls->next;
580: };
581: #endif /* USE_IPFW */
582:
583: };
584:
585: /* Bring up system interface */
586: IfaceChangeFlags(b, 0, IFF_UP | (ready?0:IFF_LINK0));
587:
588: /* Send any cached packets */
589: IfaceCacheSend(b);
590:
591: }
592:
593: /*
594: * IfaceDown()
595: *
596: * Our packet transport mechanism is no longer ready for traffic.
597: */
598:
599: void
600: IfaceDown(Bund b)
601: {
602: IfaceState const iface = &b->iface;
603: #ifdef USE_IPFW
604: struct acl_pool **rp, *rp1;
605: char cb[32768];
606: struct acl *acl, *aclnext;
607: #endif
608:
609: Log(LG_IFACE, ("[%s] IFACE: Down event", b->name));
610:
611: /* Bring down system interface */
612: IfaceChangeFlags(b, IFF_UP | IFF_LINK0, 0);
613:
614: TimerStop(&iface->idleTimer);
615: TimerStop(&iface->sessionTimer);
616:
617: #ifdef USE_IPFW
618: /* Remove rule ACLs */
619: rp = &rule_pool;
620: cb[0]=0;
621: while (*rp != NULL) {
622: if (strncmp((*rp)->ifname, iface->ifname, IFNAMSIZ) == 0) {
623: sprintf(cb+strlen(cb), " %d", (*rp)->real_number);
624: rp1 = *rp;
625: *rp = (*rp)->next;
626: Freee(rp1);
627: } else {
628: rp = &((*rp)->next);
629: };
630: };
631: if (cb[0]!=0)
632: ExecCmdNosh(LG_IFACE2, b->name, "%s delete%s",
633: PATH_IPFW, cb);
634:
635: /* Remove table ACLs */
636: rp = &table_pool;
637: while (*rp != NULL) {
638: if (strncmp((*rp)->ifname, iface->ifname, IFNAMSIZ) == 0) {
639: rp1 = *rp;
640: *rp = (*rp)->next;
641: Freee(rp1);
642: } else {
643: rp = &((*rp)->next);
644: };
645: };
646: acl = iface->tables;
647: while (acl != NULL) {
648: ExecCmd(LG_IFACE2, b->name, "%s table %d delete %s",
649: PATH_IPFW, acl->real_number, acl->rule);
650: aclnext = acl->next;
651: Freee(acl);
652: acl = aclnext;
653: };
654: iface->tables = NULL;
655:
656: /* Remove queue ACLs */
657: rp = &queue_pool;
658: cb[0]=0;
659: while (*rp != NULL) {
660: if (strncmp((*rp)->ifname, iface->ifname, IFNAMSIZ) == 0) {
661: sprintf(cb+strlen(cb), " %d", (*rp)->real_number);
662: rp1 = *rp;
663: *rp = (*rp)->next;
664: Freee(rp1);
665: } else {
666: rp = &((*rp)->next);
667: };
668: };
669: if (cb[0]!=0)
670: ExecCmdNosh(LG_IFACE2, b->name, "%s queue delete%s",
671: PATH_IPFW, cb);
672:
673: /* Remove pipe ACLs */
674: rp = &pipe_pool;
675: cb[0]=0;
676: while (*rp != NULL) {
677: if (strncmp((*rp)->ifname, iface->ifname, IFNAMSIZ) == 0) {
678: sprintf(cb+strlen(cb), " %d", (*rp)->real_number);
679: rp1 = *rp;
680: *rp = (*rp)->next;
681: Freee(rp1);
682: } else {
683: rp = &((*rp)->next);
684: };
685: };
686: if (cb[0]!=0)
687: ExecCmdNosh(LG_IFACE2, b->name, "%s pipe delete%s",
688: PATH_IPFW, cb);
689: #endif /* USE_IPFW */
690:
691: /* Revert interface name and description */
692:
693: if (strcmp(iface->ngname, iface->ifname) != 0) {
694: if (iface->conf.ifname[0] != 0) {
695: /* Restore to config defined */
696: if (IfaceSetName(b, iface->conf.ifname) != -1)
697: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Rename interface %s to %s",
698: b->name, iface->ifname, iface->conf.ifname));
699: } else {
700: /* Restore to original interface name */
701: if (IfaceSetName(b, iface->ngname) != -1)
702: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Rename interface %s to %s",
703: b->name, iface->ifname, iface->ngname));
704: }
705: }
706: #ifdef SIOCSIFDESCR
707: if (iface->ifdescr != NULL) {
708: if (iface->conf.ifdescr != NULL) {
709: /* Restore to config defined */
710: if (IfaceSetDescr(b, iface->conf.ifdescr) != -1) {
711: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Set description \"%s\"",
712: b->name, iface->conf.ifdescr));
713: iface->ifdescr = iface->conf.ifdescr;
714: } else
715: iface->ifdescr = NULL;
716: } else {
717: /* Restore to original (empty) */
718: if (IfaceSetDescr(b, "") != -1) {
719: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Clear description",
720: b->name));
721: }
722: iface->ifdescr = NULL;
723: }
724: }
725: #endif
726: #ifdef SIOCAIFGROUP
727: if (b->params.ifgroup[0] != 0) {
728: if (IfaceDelGroup(b, b->params.ifgroup) != -1)
729: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Remove group %s from %s",
730: b->name, b->params.ifgroup, iface->ngname));
731: }
732: #endif
733: }
734:
735: /*
736: * IfaceListenInput()
737: *
738: * A packet was received on our demand snooping hook. Stimulate a connection.
739: */
740:
741: void
742: IfaceListenInput(Bund b, int proto, Mbuf pkt)
743: {
744: IfaceState const iface = &b->iface;
745: int const isDemand = IfaceIsDemand(proto, pkt);
746:
747: /* Does this count as demand traffic? */
748: if (iface->open && isDemand) {
749: iface->traffic[0] = TRUE;
750: Log(LG_IFACE, ("[%s] IFACE: Outgoing %s packet demands connection", b->name,
751: (proto==PROTO_IP)?"IP":"IPv6"));
752: RecordLinkUpDownReason(b, NULL, 1, STR_DEMAND, NULL);
753: BundOpen(b);
754: IfaceCachePkt(b, proto, pkt);
755: } else {
756: mbfree(pkt);
757: }
758: }
759:
760: #ifdef USE_IPFW
761: /*
762: * IfaceAllocACL ()
763: *
764: * Allocates unique real number for new ACL and adds it to the list of used ones.
765: */
766:
767: static int
768: IfaceAllocACL(struct acl_pool ***ap, int start, char *ifname, int number)
769: {
770: int i;
771: struct acl_pool **rp,*rp1;
772:
773: rp1 = Malloc(MB_IFACE, sizeof(struct acl_pool));
774: strlcpy(rp1->ifname, ifname, sizeof(rp1->ifname));
775: rp1->acl_number = number;
776:
777: rp = *ap;
778: i = start;
779: while (*rp != NULL && (*rp)->real_number <= i) {
780: i = (*rp)->real_number+1;
781: rp = &((*rp)->next);
782: };
783: if (*rp == NULL) {
784: rp1->next = NULL;
785: } else {
786: rp1->next = *rp;
787: };
788: rp1->real_number = i;
789: *rp = rp1;
790: *ap = rp;
791: return(i);
792: }
793:
794: /*
795: * IfaceFindACL ()
796: *
797: * Finds ACL in the list and gets its real number.
798: */
799:
800: static int
801: IfaceFindACL (struct acl_pool *ap, char * ifname, int number)
802: {
803: int i;
804: struct acl_pool *rp;
805:
806: rp=ap;
807: i=-1;
808: while (rp != NULL) {
809: if ((rp->acl_number == number) && (strncmp(rp->ifname,ifname,IFNAMSIZ) == 0)) {
810: i = rp->real_number;
811: break;
812: };
813: rp = rp->next;
814: };
815: return(i);
816: }
817:
818: /*
819: * IFaceParseACL ()
820: *
821: * Parces ACL and replaces %r, %p and %q macroses
822: * by the real numbers of rules, queues and pipes.
823: */
824:
825: static char *
826: IFaceParseACL (char * src, char * ifname)
827: {
828: char *buf,*buf1;
829: char *begin,*param,*end;
830: char t;
831: int num,real_number;
832: struct acl_pool *ap;
833:
834: buf = Malloc(MB_IFACE, ACL_LEN);
835: buf1 = Malloc(MB_IFACE, ACL_LEN);
836:
837: strlcpy(buf, src, ACL_LEN);
838: do {
839: end = buf;
840: begin = strsep(&end, "%");
841: param = strsep(&end, " ");
842: if (param != NULL) {
843: if (sscanf(param,"%c%d", &t, &num) == 2) {
844: switch (t) {
845: case 'r':
846: ap = rule_pool;
847: break;
848: case 'p':
849: ap = pipe_pool;
850: break;
851: case 'q':
852: ap = queue_pool;
853: break;
854: case 't':
855: ap = table_pool;
856: break;
857: default:
858: ap = NULL;
859: };
860: real_number = IfaceFindACL(ap,ifname,num);
861: if (end != NULL) {
862: snprintf(buf1, ACL_LEN, "%s%d %s", begin, real_number, end);
863: } else {
864: snprintf(buf1, ACL_LEN, "%s%d", begin, real_number);
865: };
866: strlcpy(buf, buf1, ACL_LEN);
867: };
868: };
869: } while (end != NULL);
870: Freee(buf1);
871: return(buf);
872: }
873: #endif /* USE_IPFW */
874:
875: /*
876: * IfaceIpIfaceUp()
877: *
878: * Bring up the IP interface. The "ready" flag means that
879: * IPCP is also up and we can deliver packets immediately.
880: */
881:
882: int
883: IfaceIpIfaceUp(Bund b, int ready)
884: {
885: IfaceState const iface = &b->iface;
886: struct sockaddr_dl hwa;
887: char hisaddr[20];
888: IfaceRoute r;
889: u_char *ether;
890:
891: if (ready && !iface->conf.self_addr_force) {
892: in_addrtou_range(&b->ipcp.want_addr, 32, &iface->self_addr);
893: } else {
894: u_rangecopy(&iface->conf.self_addr, &iface->self_addr);
895: }
896: if (ready && !iface->conf.peer_addr_force) {
897: in_addrtou_addr(&b->ipcp.peer_addr, &iface->peer_addr);
898: } else {
899: u_addrcopy(&iface->conf.peer_addr, &iface->peer_addr);
900: }
901:
902: if (IfaceNgIpInit(b, ready)) {
903: Log(LG_ERR, ("[%s] IFACE: IfaceNgIpInit() error, closing IPCP", b->name));
904: FsmFailure(&b->ipcp.fsm, FAIL_NEGOT_FAILURE);
905: return (-1);
906: };
907:
908: /* Set addresses */
909: if (!u_rangeempty(&iface->self_addr) &&
910: IfaceChangeAddr(b, 1, &iface->self_addr, &iface->peer_addr)) {
911: Log(LG_ERR, ("[%s] IFACE: IfaceChangeAddr() error, closing IPCP", b->name));
912: FsmFailure(&b->ipcp.fsm, FAIL_NEGOT_FAILURE);
913: return (-1);
914: };
915:
916: /* Proxy ARP for peer if desired and peer's address is known */
917: u_addrclear(&iface->proxy_addr);
918: if (Enabled(&iface->options, IFACE_CONF_PROXY)) {
919: if (u_addrempty(&iface->peer_addr)) {
920: Log(LG_IFACE,
921: ("[%s] IFACE: Can't proxy arp for %s",
922: b->name, u_addrtoa(&iface->peer_addr,hisaddr,sizeof(hisaddr))));
923: } else if (GetEther(&iface->peer_addr, &hwa) < 0) {
924: Log(LG_IFACE,
925: ("[%s] IFACE: No interface to proxy arp on for %s",
926: b->name, u_addrtoa(&iface->peer_addr,hisaddr,sizeof(hisaddr))));
927: } else {
928: ether = (u_char *) LLADDR(&hwa);
929: if (ExecCmdNosh(LG_IFACE2, b->name,
930: "%s -S %s %x:%x:%x:%x:%x:%x pub",
931: PATH_ARP, u_addrtoa(&iface->peer_addr,hisaddr,sizeof(hisaddr)),
932: ether[0], ether[1], ether[2],
933: ether[3], ether[4], ether[5]) == 0)
934: iface->proxy_addr = iface->peer_addr;
935: }
936: }
937:
938: /* Add static routes */
939: SLIST_FOREACH(r, &iface->routes, next) {
940: if (u_rangefamily(&r->dest)==AF_INET) {
941: r->ok = (IfaceSetRoute(b, RTM_ADD, &r->dest, &iface->peer_addr) == 0);
942: }
943: }
944: /* Add dynamic routes */
945: SLIST_FOREACH(r, &b->params.routes, next) {
946: if (u_rangefamily(&r->dest)==AF_INET) {
947: r->ok = (IfaceSetRoute(b, RTM_ADD, &r->dest, &iface->peer_addr) == 0);
948: }
949: }
950:
951: #ifdef USE_NG_NAT
952: /* Set NAT IP */
953: if (iface->nat_up)
954: IfaceSetupNAT(b);
955: #endif
956:
957: /* Call "up" script */
958: if (*iface->up_script) {
959: char selfbuf[40],peerbuf[40];
960: char ns1buf[21], ns2buf[21];
961: int res;
962:
963: if(b->ipcp.want_dns[0].s_addr != 0)
964: snprintf(ns1buf, sizeof(ns1buf), "dns1 %s", inet_ntoa(b->ipcp.want_dns[0]));
965: else
966: ns1buf[0] = '\0';
967: if(b->ipcp.want_dns[1].s_addr != 0)
968: snprintf(ns2buf, sizeof(ns2buf), "dns2 %s", inet_ntoa(b->ipcp.want_dns[1]));
969: else
970: ns2buf[0] = '\0';
971:
972: res = ExecCmd(LG_IFACE2, b->name, "%s %s inet %s %s '%s' '%s' '%s' '%s'",
973: iface->up_script, iface->ifname, u_rangetoa(&iface->self_addr,selfbuf, sizeof(selfbuf)),
974: u_addrtoa(&iface->peer_addr, peerbuf, sizeof(peerbuf)),
975: *b->params.authname ? b->params.authname : "-",
976: ns1buf, ns2buf, *b->params.peeraddr ? b->params.peeraddr : "-");
977: if (res != 0) {
978: FsmFailure(&b->ipcp.fsm, FAIL_NEGOT_FAILURE);
979: return (-1);
980: }
981: }
982: return (0);
983: }
984:
985: /*
986: * IfaceIpIfaceDown()
987: *
988: * Bring down the IP interface. This implies we're no longer ready.
989: */
990:
991: void
992: IfaceIpIfaceDown(Bund b)
993: {
994: IfaceState const iface = &b->iface;
995: IfaceRoute r;
996: char buf[48];
997:
998: /* Call "down" script */
999: if (*iface->down_script) {
1000: char selfbuf[40],peerbuf[40];
1001:
1002: ExecCmd(LG_IFACE2, b->name, "%s %s inet %s %s '%s' '%s'",
1003: iface->down_script, iface->ifname, u_rangetoa(&iface->self_addr,selfbuf, sizeof(selfbuf)),
1004: u_addrtoa(&iface->peer_addr, peerbuf, sizeof(peerbuf)),
1005: *b->params.authname ? b->params.authname : "-",
1006: *b->params.peeraddr ? b->params.peeraddr : "-");
1007: }
1008:
1009: /* Delete dynamic routes */
1010: SLIST_FOREACH(r, &b->params.routes, next) {
1011: if (u_rangefamily(&r->dest)==AF_INET) {
1012: if (!r->ok)
1013: continue;
1014: IfaceSetRoute(b, RTM_DELETE, &r->dest, &iface->peer_addr);
1015: r->ok = 0;
1016: }
1017: }
1018: /* Delete static routes */
1019: SLIST_FOREACH(r, &iface->routes, next) {
1020: if (u_rangefamily(&r->dest)==AF_INET) {
1021: if (!r->ok)
1022: continue;
1023: IfaceSetRoute(b, RTM_DELETE, &r->dest, &iface->peer_addr);
1024: r->ok = 0;
1025: }
1026: }
1027:
1028: /* Delete any proxy arp entry */
1029: if (!u_addrempty(&iface->proxy_addr))
1030: ExecCmdNosh(LG_IFACE2, b->name, "%s -d %s", PATH_ARP, u_addrtoa(&iface->proxy_addr, buf, sizeof(buf)));
1031: u_addrclear(&iface->proxy_addr);
1032:
1033: /* Remove address from interface */
1034: if (!u_rangeempty(&iface->self_addr))
1035: IfaceChangeAddr(b, 0, &iface->self_addr, &iface->peer_addr);
1036:
1037: IfaceNgIpShutdown(b);
1038: }
1039:
1040: /*
1041: * IfaceIpv6IfaceUp()
1042: *
1043: * Bring up the IPv6 interface. The "ready" flag means that
1044: * IPv6CP is also up and we can deliver packets immediately.
1045: */
1046:
1047: int
1048: IfaceIpv6IfaceUp(Bund b, int ready)
1049: {
1050: IfaceState const iface = &b->iface;
1051: IfaceRoute r;
1052:
1053: if (ready && !iface->conf.self_ipv6_addr_force) {
1054: iface->self_ipv6_addr.family = AF_INET6;
1055: iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[0] = 0x80fe; /* Network byte order */
1056: iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[1] = 0x0000;
1057: iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[2] = 0x0000;
1058: iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[3] = 0x0000;
1059: iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[4] = ((u_short*)b->ipv6cp.myintid)[0];
1060: iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[5] = ((u_short*)b->ipv6cp.myintid)[1];
1061: iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[6] = ((u_short*)b->ipv6cp.myintid)[2];
1062: iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[7] = ((u_short*)b->ipv6cp.myintid)[3];
1063: } else {
1064: u_addrcopy(&iface->conf.self_ipv6_addr, &iface->self_ipv6_addr);
1065: }
1066: if (ready && !iface->conf.peer_ipv6_addr_force) {
1067: iface->peer_ipv6_addr.family = AF_INET6;
1068: iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[0] = 0x80fe; /* Network byte order */
1069: iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[1] = 0x0000;
1070: iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[2] = 0x0000;
1071: iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[3] = 0x0000;
1072: iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[4] = ((u_short*)b->ipv6cp.hisintid)[0];
1073: iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[5] = ((u_short*)b->ipv6cp.hisintid)[1];
1074: iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[6] = ((u_short*)b->ipv6cp.hisintid)[2];
1075: iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[7] = ((u_short*)b->ipv6cp.hisintid)[3];
1076: } else {
1077: u_addrcopy(&iface->conf.peer_ipv6_addr, &iface->peer_ipv6_addr);
1078: }
1079:
1080: if (IfaceNgIpv6Init(b, ready)) {
1081: Log(LG_ERR, ("[%s] IFACE: IfaceNgIpv6Init() failed, closing IPv6CP", b->name));
1082: FsmFailure(&b->ipv6cp.fsm, FAIL_NEGOT_FAILURE);
1083: return (-1);
1084: };
1085:
1086: /* Set addresses */
1087: if (!u_addrempty(&iface->self_ipv6_addr)) {
1088: struct u_range rng;
1089: rng.addr = iface->self_ipv6_addr;
1090: rng.width = 64;
1091: if (IfaceChangeAddr(b, 1, &rng, &iface->peer_ipv6_addr)) {
1092: Log(LG_ERR, ("[%s] IFACE: IfaceChangeAddr() failed, closing IPv6CP", b->name));
1093: FsmFailure(&b->ipv6cp.fsm, FAIL_NEGOT_FAILURE);
1094: return (-1);
1095: }
1096: };
1097:
1098: /* Add static routes */
1099: SLIST_FOREACH(r, &iface->routes, next) {
1100: if (u_rangefamily(&r->dest)==AF_INET6) {
1101: r->ok = (IfaceSetRoute(b, RTM_ADD, &r->dest, &iface->peer_ipv6_addr) == 0);
1102: }
1103: }
1104: /* Add dynamic routes */
1105: SLIST_FOREACH(r, &b->params.routes, next) {
1106: if (u_rangefamily(&r->dest)==AF_INET6) {
1107: r->ok = (IfaceSetRoute(b, RTM_ADD, &r->dest, &iface->peer_ipv6_addr) == 0);
1108: }
1109: }
1110:
1111: /* Call "up" script */
1112: if (*iface->up_script) {
1113: char selfbuf[48],peerbuf[48];
1114: int res;
1115:
1116: res = ExecCmd(LG_IFACE2, b->name, "%s %s inet6 %s%%%s %s%%%s '%s' '%s'",
1117: iface->up_script, iface->ifname,
1118: u_addrtoa(&iface->self_ipv6_addr, selfbuf, sizeof(selfbuf)), iface->ifname,
1119: u_addrtoa(&iface->peer_ipv6_addr, peerbuf, sizeof(peerbuf)), iface->ifname,
1120: *b->params.authname ? b->params.authname : "-",
1121: *b->params.peeraddr ? b->params.peeraddr : "-");
1122: if (res != 0) {
1123: FsmFailure(&b->ipv6cp.fsm, FAIL_NEGOT_FAILURE);
1124: return (-1);
1125: }
1126: }
1127: return (0);
1128:
1129: }
1130:
1131: /*
1132: * IfaceIpv6IfaceDown()
1133: *
1134: * Bring down the IPv6 interface. This implies we're no longer ready.
1135: */
1136:
1137: void
1138: IfaceIpv6IfaceDown(Bund b)
1139: {
1140: IfaceState const iface = &b->iface;
1141: IfaceRoute r;
1142: struct u_range rng;
1143:
1144: /* Call "down" script */
1145: if (*iface->down_script) {
1146: char selfbuf[48],peerbuf[48];
1147:
1148: ExecCmd(LG_IFACE2, b->name, "%s %s inet6 %s%%%s %s%%%s '%s' '%s'",
1149: iface->down_script, iface->ifname,
1150: u_addrtoa(&iface->self_ipv6_addr, selfbuf, sizeof(selfbuf)), iface->ifname,
1151: u_addrtoa(&iface->peer_ipv6_addr, peerbuf, sizeof(peerbuf)), iface->ifname,
1152: *b->params.authname ? b->params.authname : "-",
1153: *b->params.peeraddr ? b->params.peeraddr : "-");
1154: }
1155:
1156: /* Delete dynamic routes */
1157: SLIST_FOREACH(r, &b->params.routes, next) {
1158: if (u_rangefamily(&r->dest)==AF_INET6) {
1159: if (!r->ok)
1160: continue;
1161: IfaceSetRoute(b, RTM_DELETE, &r->dest, &iface->peer_ipv6_addr);
1162: r->ok = 0;
1163: }
1164: }
1165: /* Delete static routes */
1166: SLIST_FOREACH(r, &iface->routes, next) {
1167: if (u_rangefamily(&r->dest)==AF_INET6) {
1168: if (!r->ok)
1169: continue;
1170: IfaceSetRoute(b, RTM_DELETE, &r->dest, &iface->peer_ipv6_addr);
1171: r->ok = 0;
1172: }
1173: }
1174:
1175: if (!u_addrempty(&iface->self_ipv6_addr)) {
1176: /* Remove address from interface */
1177: rng.addr = iface->self_ipv6_addr;
1178: rng.width = 64;
1179: IfaceChangeAddr(b, 0, &rng, &iface->peer_ipv6_addr);
1180: }
1181:
1182: IfaceNgIpv6Shutdown(b);
1183: }
1184:
1185: /*
1186: * IfaceIdleTimeout()
1187: */
1188:
1189: static void
1190: IfaceIdleTimeout(void *arg)
1191: {
1192: Bund b = (Bund)arg;
1193:
1194: IfaceState const iface = &b->iface;
1195: int k;
1196:
1197: /* Get updated bpf node traffic statistics */
1198: BundUpdateStats(b);
1199:
1200: /* Mark current traffic period if there was traffic */
1201: if (iface->idleStats.recvFrames + iface->idleStats.xmitFrames <
1202: b->stats.recvFrames + b->stats.xmitFrames) {
1203: iface->traffic[0] = TRUE;
1204: } else { /* no demand traffic for a whole idle timeout period? */
1205: for (k = 0; k < IFACE_IDLE_SPLIT && !iface->traffic[k]; k++);
1206: if (k == IFACE_IDLE_SPLIT) {
1207: Log(LG_BUND, ("[%s] IFACE: Idle timeout", b->name));
1208: RecordLinkUpDownReason(b, NULL, 0, STR_IDLE_TIMEOUT, NULL);
1209: BundClose(b);
1210: return;
1211: }
1212: }
1213:
1214: iface->idleStats = b->stats;
1215:
1216: /* Shift traffic history */
1217: memmove(iface->traffic + 1,
1218: iface->traffic, (IFACE_IDLE_SPLIT - 1) * sizeof(*iface->traffic));
1219: iface->traffic[0] = FALSE;
1220:
1221: /* Restart timer */
1222: TimerStart(&iface->idleTimer);
1223: }
1224:
1225: /*
1226: * IfaceSessionTimeout()
1227: */
1228:
1229: static void
1230: IfaceSessionTimeout(void *arg)
1231: {
1232: Bund b = (Bund)arg;
1233:
1234: Log(LG_BUND, ("[%s] IFACE: Session timeout", b->name));
1235:
1236: RecordLinkUpDownReason(b, NULL, 0, STR_SESSION_TIMEOUT, NULL);
1237:
1238: BundClose(b);
1239:
1240: }
1241:
1242: /*
1243: * IfaceCachePkt()
1244: *
1245: * A packet caused dial-on-demand; save it for later if possible.
1246: * Consumes the mbuf in any case.
1247: */
1248:
1249: static void
1250: IfaceCachePkt(Bund b, int proto, Mbuf pkt)
1251: {
1252: IfaceState const iface = &b->iface;
1253:
1254: /* Only cache network layer data */
1255: if (!PROT_NETWORK_DATA(proto)) {
1256: mbfree(pkt);
1257: return;
1258: }
1259:
1260: /* Release previously cached packet, if any, and save this one */
1261: if (iface->dodCache.pkt)
1262: mbfree(iface->dodCache.pkt);
1263:
1264: iface->dodCache.pkt = pkt;
1265: iface->dodCache.proto = proto;
1266: iface->dodCache.ts = time(NULL);
1267: }
1268:
1269: /*
1270: * IfaceCacheSend()
1271: *
1272: * Send cached packet
1273: */
1274:
1275: static void
1276: IfaceCacheSend(Bund b)
1277: {
1278: IfaceState const iface = &b->iface;
1279:
1280: if (iface->dodCache.pkt) {
1281: if (iface->dodCache.ts + MAX_DOD_CACHE_DELAY < time(NULL))
1282: mbfree(iface->dodCache.pkt);
1283: else {
1284: if (NgFuncWritePppFrame(b, NG_PPP_BUNDLE_LINKNUM,
1285: iface->dodCache.proto, iface->dodCache.pkt) < 0) {
1286: Perror("[%s] can't write cached pkt", b->name);
1287: }
1288: }
1289: iface->dodCache.pkt = NULL;
1290: }
1291: }
1292:
1293: /*
1294: * IfaceIsDemand()
1295: *
1296: * Determine if this outgoing packet qualifies for dial-on-demand
1297: */
1298:
1299: static int
1300: IfaceIsDemand(int proto, Mbuf pkt)
1301: {
1302: switch (proto) {
1303: case PROTO_IP:
1304: {
1305: struct ip *ip;
1306:
1307: if (MBLEN(pkt) < sizeof(struct ip))
1308: return (0);
1309:
1310: ip = (struct ip *)MBDATA(pkt);
1311: switch (ip->ip_p) {
1312: case IPPROTO_IGMP: /* No multicast stuff */
1313: return(0);
1314: #if (!defined(__FreeBSD__) || __FreeBSD_version >= 600025)
1315: case IPPROTO_ICMP:
1316: {
1317: struct icmphdr *icmp;
1318:
1319: if (MBLEN(pkt) < (ip->ip_hl * 4 + sizeof(struct icmphdr)))
1320: return (0);
1321:
1322: icmp = (struct icmphdr *) ((u_int32_t *) ip + ip->ip_hl);
1323:
1324: switch (icmp->icmp_type) /* No ICMP replies */
1325: {
1326: case ICMP_ECHOREPLY:
1327: case ICMP_UNREACH:
1328: case ICMP_REDIRECT:
1329: return(0);
1330: default:
1331: break;
1332: }
1333: }
1334: break;
1335: #endif
1336: case IPPROTO_UDP:
1337: {
1338: struct udphdr *udp;
1339:
1340: if (MBLEN(pkt) < (ip->ip_hl * 4 + sizeof(struct udphdr)))
1341: return (0);
1342:
1343: udp = (struct udphdr *) ((u_int32_t *) ip + ip->ip_hl);
1344:
1345: #define NTP_PORT 123
1346: if (ntohs(udp->uh_dport) == NTP_PORT) /* No NTP packets */
1347: return(0);
1348: }
1349: break;
1350: case IPPROTO_TCP:
1351: {
1352: struct tcphdr *tcp;
1353:
1354: if (MBLEN(pkt) < (ip->ip_hl * 4 + sizeof(struct tcphdr)))
1355: return (0);
1356:
1357: tcp = (struct tcphdr *) ((u_int32_t *) ip + ip->ip_hl);
1358:
1359: if (tcp->th_flags & TH_RST) /* No TCP reset packets */
1360: return(0);
1361: }
1362: break;
1363: default:
1364: break;
1365: }
1366: break;
1367: }
1368: default:
1369: break;
1370: }
1371: return(1);
1372: }
1373:
1374: /*
1375: * IfaceSetCommand()
1376: */
1377:
1378: static int
1379: IfaceSetCommand(Context ctx, int ac, char *av[], void *arg)
1380: {
1381: IfaceState const iface = &ctx->bund->iface;
1382: int empty_arg;
1383:
1384: switch ((intptr_t)arg) {
1385: case SET_NAME:
1386: #ifdef SIOCSIFDESCR
1387: case SET_DESCR:
1388: #endif
1389: case SET_UP_SCRIPT:
1390: case SET_DOWN_SCRIPT:
1391: empty_arg = TRUE;
1392: break;
1393: default:
1394: empty_arg = FALSE;
1395: break;
1396: }
1397:
1398: if ((ac == 0) && (empty_arg == FALSE))
1399: return(-1);
1400: switch ((intptr_t)arg) {
1401: case SET_IDLE:
1402: iface->idle_timeout = atoi(*av);
1403: break;
1404: case SET_SESSION:
1405: iface->session_timeout = atoi(*av);
1406: break;
1407: case SET_ADDRS:
1408: {
1409: struct u_range self_addr;
1410: struct u_addr peer_addr;
1411: int self_addr_force = 0, peer_addr_force = 0;
1412: char *arg;
1413:
1414: /* Parse */
1415: if (ac != 2)
1416: return(-1);
1417: arg = av[0];
1418: if (arg[0] == '!') {
1419: self_addr_force = 1;
1420: arg++;
1421: }
1422: if (!ParseRange(arg, &self_addr, ALLOW_IPV4|ALLOW_IPV6))
1423: Error("Bad IP address \"%s\"", av[0]);
1424: arg = av[1];
1425: if (arg[0] == '!') {
1426: peer_addr_force = 1;
1427: arg++;
1428: }
1429: if (!ParseAddr(arg, &peer_addr, ALLOW_IPV4|ALLOW_IPV6))
1430: Error("Bad IP address \"%s\"", av[1]);
1431: if (self_addr.addr.family != peer_addr.family)
1432: Error("Addresses must be from the same protocol family");
1433:
1434: /* OK */
1435: if (peer_addr.family == AF_INET) {
1436: iface->conf.self_addr = self_addr;
1437: iface->conf.peer_addr = peer_addr;
1438: iface->conf.self_addr_force = self_addr_force;
1439: iface->conf.peer_addr_force = peer_addr_force;
1440: } else {
1441: iface->conf.self_ipv6_addr = self_addr.addr;
1442: iface->conf.peer_ipv6_addr = peer_addr;
1443: iface->conf.self_ipv6_addr_force = self_addr_force;
1444: iface->conf.peer_ipv6_addr_force = peer_addr_force;
1445: }
1446: }
1447: break;
1448:
1449: case SET_ROUTE:
1450: {
1451: struct u_range range;
1452: IfaceRoute r;
1453:
1454: /* Check */
1455: if (ac != 1)
1456: return(-1);
1457:
1458: /* Get dest address */
1459: if (!strcasecmp(av[0], "default")) {
1460: u_rangeclear(&range);
1461: range.addr.family=AF_INET;
1462: }
1463: else if (!ParseRange(av[0], &range, ALLOW_IPV4|ALLOW_IPV6))
1464: Error("Bad route dest address \"%s\"", av[0]);
1465: r = Malloc(MB_IFACE, sizeof(struct ifaceroute));
1466: r->dest = range;
1467: r->ok = 0;
1468: SLIST_INSERT_HEAD(&iface->routes, r, next);
1469: }
1470: break;
1471:
1472: case SET_MTU:
1473: {
1474: int max_mtu;
1475:
1476: /* Check */
1477: if (ac != 1)
1478: return(-1);
1479:
1480: max_mtu = atoi(av[0]);
1481: if (max_mtu < IFACE_MIN_MTU || max_mtu > IFACE_MAX_MTU)
1482: Error("Invalid interface mtu %d", max_mtu);
1483: iface->max_mtu = max_mtu;
1484: }
1485: break;
1486:
1487: case SET_NAME:
1488: switch (ac) {
1489: case 0:
1490: /* Restore original interface name */
1491: if (strcmp(iface->ifname, iface->ngname) != 0) {
1492: iface->conf.ifname[0] = '\0';
1493: return IfaceSetName(ctx->bund, iface->ngname);
1494: }
1495: break;
1496: case 1:
1497: if (strcmp(iface->ifname, av[0]) != 0) {
1498: int ifmaxlen = IF_NAMESIZE - ctx->bund->tmpl * IFNUMLEN;
1499: if (strlen(av[0]) >= ifmaxlen)
1500: Error("Interface name too long, >%d characters", ifmaxlen-1);
1501: if ((strncmp(av[0], "ng", 2) == 0) &&
1502: ((ctx->bund->tmpl && av[0][2] == 0) ||
1503: (av[0][2] >= '0' && av[0][2] <= '9')))
1504: Error("This interface name is reserved");
1505: strlcpy(iface->conf.ifname, av[0], sizeof(iface->conf.ifname));
1506: return IfaceSetName(ctx->bund, av[0]);
1507: }
1508: break;
1509: default:
1510: return(-1);
1511: }
1512: break;
1513: #ifdef SIOCSIFDESCR
1514: case SET_DESCR:
1515: if (ctx->bund->tmpl)
1516: Error("Impossible to apply on template");
1517: if (iface->conf.ifdescr != NULL)
1518: Freee(iface->conf.ifdescr);
1519: iface->conf.ifdescr = NULL;
1520: iface->ifdescr = NULL;
1521: switch (ac) {
1522: case 0:
1523: return IfaceSetDescr(ctx->bund, "");
1524: break;
1525: case 1:
1526: iface->conf.ifdescr = Mstrdup(MB_IFACE, av[0]);
1527: if (IfaceSetDescr(ctx->bund, av[0]) == 0) {
1528: iface->ifdescr = iface->conf.ifdescr;
1529: return(0);
1530: } else
1531: return(-1);
1532: break;
1533: default:
1534: return(-1);
1535: }
1536: break;
1537: #endif
1538: #ifdef SIOCAIFGROUP
1539: case SET_GROUP:
1540: if (ac != 1)
1541: return(-1);
1542:
1543: if (av[0][0] && isdigit(av[0][strlen(av[0]) - 1]))
1544: Error("Groupnames may not end in a digit");
1545: if (strlen(av[0]) >= IFNAMSIZ)
1546: Error("Group name %s too long", av[0]);
1547: if (iface->conf.ifgroup[0] != 0)
1548: IfaceDelGroup(ctx->bund, iface->conf.ifgroup);
1549: strlcpy(iface->conf.ifgroup, av[0], IFNAMSIZ);
1550: return IfaceAddGroup(ctx->bund, av[0]);
1551: break;
1552: #endif
1553: case SET_UP_SCRIPT:
1554: switch (ac) {
1555: case 0:
1556: *iface->up_script = 0;
1557: break;
1558: case 1:
1559: strlcpy(iface->up_script, av[0], sizeof(iface->up_script));
1560: break;
1561: default:
1562: return(-1);
1563: }
1564: break;
1565:
1566: case SET_DOWN_SCRIPT:
1567: switch (ac) {
1568: case 0:
1569: *iface->down_script = 0;
1570: break;
1571: case 1:
1572: strlcpy(iface->down_script, av[0], sizeof(iface->down_script));
1573: break;
1574: default:
1575: return(-1);
1576: }
1577: break;
1578:
1579: case SET_ENABLE:
1580: EnableCommand(ac, av, &iface->options, gConfList);
1581: break;
1582:
1583: case SET_DISABLE:
1584: DisableCommand(ac, av, &iface->options, gConfList);
1585: break;
1586:
1587: default:
1588: assert(0);
1589: }
1590: return(0);
1591: }
1592:
1593: /*
1594: * IfaceStat()
1595: */
1596:
1597: int
1598: IfaceStat(Context ctx, int ac, char *av[], void *arg)
1599: {
1600: Bund const b = ctx->bund;
1601: IfaceState const iface = &b->iface;
1602: IfaceRoute r;
1603: #ifdef USE_NG_BPF
1604: int k;
1605: #endif
1606: char buf[48];
1607: #if defined(USE_NG_BPF) || defined(USE_IPFW)
1608: struct acl *a;
1609: #endif
1610:
1611: Printf("Interface configuration:\r\n");
1612: Printf("\tName : %s\r\n", iface->conf.ifname);
1613: #ifdef SIOCSIFDESCR
1614: Printf("\tDescription : \"%s\"\r\n",
1615: (iface->conf.ifdescr != NULL) ? iface->conf.ifdescr : "<none>");
1616: #endif
1617: #ifdef SIOCAIFGROUP
1618: Printf("\tGroup : %s\r\n", iface->conf.ifgroup);
1619: #endif
1620: Printf("\tMaximum MTU : %d bytes\r\n", iface->max_mtu);
1621: Printf("\tIdle timeout : %d seconds\r\n", iface->idle_timeout);
1622: Printf("\tSession timeout : %d seconds\r\n", iface->session_timeout);
1623: if (!u_rangeempty(&iface->conf.self_addr)) {
1624: Printf("\tIP Addresses : %s%s -> ", iface->conf.self_addr_force?"!":"",
1625: u_rangetoa(&iface->conf.self_addr,buf,sizeof(buf)));
1626: Printf("%s%s\r\n", iface->conf.peer_addr_force?"!":"",
1627: u_addrtoa(&iface->conf.peer_addr,buf,sizeof(buf)));
1628: }
1629: if (!u_addrempty(&iface->conf.self_ipv6_addr)) {
1630: Printf("\tIPv6 Addresses : %s%s%%%s -> ", iface->conf.self_ipv6_addr_force?"!":"",
1631: u_addrtoa(&iface->conf.self_ipv6_addr,buf,sizeof(buf)), iface->ifname);
1632: Printf("%s%s%%%s\r\n", iface->conf.peer_ipv6_addr_force?"!":"",
1633: u_addrtoa(&iface->conf.peer_ipv6_addr,buf,sizeof(buf)), iface->ifname);
1634: }
1635: Printf("\tEvent scripts\r\n");
1636: Printf("\t up-script : \"%s\"\r\n",
1637: *iface->up_script ? iface->up_script : "<none>");
1638: Printf("\t down-script : \"%s\"\r\n",
1639: *iface->down_script ? iface->down_script : "<none>");
1640: Printf("Interface options:\r\n");
1641: OptStat(ctx, &iface->options, gConfList);
1642: if (!SLIST_EMPTY(&iface->routes)) {
1643: Printf("Static routes via peer:\r\n");
1644: SLIST_FOREACH(r, &iface->routes, next) {
1645: Printf("\t%s\r\n", u_rangetoa(&r->dest,buf,sizeof(buf)));
1646: }
1647: }
1648: Printf("Interface status:\r\n");
1649: Printf("\tAdmin status : %s\r\n", iface->open ? "OPEN" : "CLOSED");
1650: Printf("\tStatus : %s\r\n", iface->up ? (iface->dod?"DoD":"UP") : "DOWN");
1651: Printf("\tName : %s\r\n", iface->ifname);
1652: #ifdef SIOCSIFDESCR
1653: Printf("\tDescription : \"%s\"\r\n",
1654: (iface->ifdescr != NULL) ? iface->ifdescr : "<none>");
1655: #endif
1656: if (iface->up) {
1657: Printf("\tSession time : %ld seconds\r\n", (long int)(time(NULL) - iface->last_up));
1658: if (b->params.idle_timeout || iface->idle_timeout)
1659: Printf("\tIdle timeout : %d seconds\r\n", b->params.idle_timeout?b->params.idle_timeout:iface->idle_timeout);
1660: if (b->params.session_timeout || iface->session_timeout)
1661: Printf("\tSession timeout : %d seconds\r\n", b->params.session_timeout?b->params.session_timeout:iface->session_timeout);
1662: Printf("\tMTU : %d bytes\r\n", iface->mtu);
1663: }
1664: if (iface->ip_up && !u_rangeempty(&iface->self_addr)) {
1665: Printf("\tIP Addresses : %s -> ", u_rangetoa(&iface->self_addr,buf,sizeof(buf)));
1666: Printf("%s\r\n", u_addrtoa(&iface->peer_addr,buf,sizeof(buf)));
1667: }
1668: if (iface->ipv6_up && !u_addrempty(&iface->self_ipv6_addr)) {
1669: Printf("\tIPv6 Addresses : %s%%%s -> ",
1670: u_addrtoa(&iface->self_ipv6_addr,buf,sizeof(buf)), iface->ifname);
1671: Printf("%s%%%s\r\n", u_addrtoa(&iface->peer_ipv6_addr,buf,sizeof(buf)), iface->ifname);
1672: }
1673: if (iface->up) {
1674: Printf("Dynamic routes via peer:\r\n");
1675: SLIST_FOREACH(r, &ctx->bund->params.routes, next) {
1676: Printf("\t%s\r\n", u_rangetoa(&r->dest,buf,sizeof(buf)));
1677: }
1678: #ifdef USE_IPFW
1679: Printf("IPFW pipes:\r\n");
1680: a = ctx->bund->params.acl_pipe;
1681: while (a) {
1682: Printf("\t%d (%d)\t: '%s'\r\n", a->number, a->real_number, a->rule);
1683: a = a->next;
1684: }
1685: Printf("IPFW queues:\r\n");
1686: a = ctx->bund->params.acl_queue;
1687: while (a) {
1688: Printf("\t%d (%d)\t: '%s'\r\n", a->number, a->real_number, a->rule);
1689: a = a->next;
1690: }
1691: Printf("IPFW tables:\r\n");
1692: a = ctx->bund->params.acl_table;
1693: while (a) {
1694: if (a->number != 0)
1695: Printf("\t%d (%d)\t: '%s'\r\n", a->number, a->real_number, a->rule);
1696: else
1697: Printf("\t(%d)\t: '%s'\r\n", a->real_number, a->rule);
1698: a = a->next;
1699: }
1700: Printf("IPFW rules:\r\n");
1701: a = ctx->bund->params.acl_rule;
1702: while (a) {
1703: Printf("\t%d (%d)\t: '%s'\r\n", a->number, a->real_number, a->rule);
1704: a = a->next;
1705: }
1706: #endif /* USE_IPFW */
1707: #ifdef USE_NG_BPF
1708: Printf("Traffic filters:\r\n");
1709: for (k = 0; k < ACL_FILTERS; k++) {
1710: a = ctx->bund->params.acl_filters[k];
1711: if (a == NULL)
1712: a = acl_filters[k];
1713: while (a) {
1714: Printf("\t%d#%d\t: '%s'\r\n", (k + 1), a->number, a->rule);
1715: a = a->next;
1716: }
1717: }
1718: Printf("Traffic limits:\r\n");
1719: for (k = 0; k < 2; k++) {
1720: a = ctx->bund->params.acl_limits[k];
1721: while (a) {
1722: Printf("\t%s#%d%s%s\t: '%s'\r\n", (k?"out":"in"), a->number,
1723: ((a->name[0])?"#":""), a->name, a->rule);
1724: a = a->next;
1725: }
1726: }
1727: #endif /* USE_NG_BPF */
1728: }
1729: return(0);
1730: }
1731:
1732: /*
1733: * IfaceSetMTU()
1734: *
1735: * Set MTU and bandwidth on bundle's interface
1736: */
1737:
1738: void
1739: IfaceSetMTU(Bund b, int mtu)
1740: {
1741: IfaceState const iface = &b->iface;
1742: struct ifreq ifr;
1743: int s;
1744:
1745: /* Get socket */
1746: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
1747: Perror("[%s] IFACE: Can't get socket to set MTU", b->name);
1748: return;
1749: }
1750:
1751: if ((b->params.mtu > 0) && (mtu > b->params.mtu)) {
1752: mtu = b->params.mtu;
1753: Log(LG_IFACE2, ("[%s] IFACE: forcing MTU of auth backend: %d bytes",
1754: b->name, mtu));
1755: }
1756:
1757: /* Limit MTU to configured maximum */
1758: if (mtu > iface->max_mtu)
1759: mtu = iface->max_mtu;
1760:
1761: /* Set MTU on interface */
1762: memset(&ifr, 0, sizeof(ifr));
1763: strlcpy(ifr.ifr_name, b->iface.ifname, sizeof(ifr.ifr_name));
1764: ifr.ifr_mtu = mtu;
1765: Log(LG_IFACE2, ("[%s] IFACE: setting %s MTU to %d bytes",
1766: b->name, b->iface.ifname, mtu));
1767: if (ioctl(s, SIOCSIFMTU, (char *)&ifr) < 0)
1768: Perror("[%s] IFACE: ioctl(%s, %s)", b->name, b->iface.ifname, "SIOCSIFMTU");
1769: close(s);
1770:
1771: /* Save MTU */
1772: iface->mtu = mtu;
1773:
1774: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
1775: /* Update tcpmssfix config */
1776: if (iface->mss_up)
1777: IfaceSetupMSS(b, MAXMSS(mtu));
1778: #endif
1779:
1780: }
1781:
1782: void
1783: IfaceChangeFlags(Bund b, int clear, int set)
1784: {
1785: struct ifreq ifrq;
1786: int s, new_flags;
1787:
1788: Log(LG_IFACE2, ("[%s] IFACE: Change interface flags: -%d +%d",
1789: b->name, clear, set));
1790:
1791: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
1792: Perror("[%s] IFACE: Can't get socket to change interface flags", b->name);
1793: return;
1794: }
1795:
1796: memset(&ifrq, '\0', sizeof(ifrq));
1797: strlcpy(ifrq.ifr_name, b->iface.ifname, sizeof(ifrq.ifr_name));
1798: ifrq.ifr_name[sizeof(ifrq.ifr_name) - 1] = '\0';
1799: if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
1800: Perror("[%s] IFACE: ioctl(%s, %s)", b->name, b->iface.ifname, "SIOCGIFFLAGS");
1801: close(s);
1802: return;
1803: }
1804: new_flags = (ifrq.ifr_flags & 0xffff) | (ifrq.ifr_flagshigh << 16);
1805:
1806: new_flags &= ~clear;
1807: new_flags |= set;
1808:
1809: ifrq.ifr_flags = new_flags & 0xffff;
1810: ifrq.ifr_flagshigh = new_flags >> 16;
1811:
1812: if (ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
1813: Perror("[%s] IFACE: ioctl(%s, %s)", b->name, b->iface.ifname, "SIOCSIFFLAGS");
1814: close(s);
1815: return;
1816: }
1817: close(s);
1818: }
1819:
1820: #if defined(__KAME__) && !defined(NOINET6)
1821: static void
1822: add_scope(struct sockaddr *sa, int ifindex)
1823: {
1824: struct sockaddr_in6 *sa6;
1825:
1826: if (sa->sa_family != AF_INET6)
1827: return;
1828: sa6 = (struct sockaddr_in6 *)sa;
1829: if (!IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) &&
1830: !IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr))
1831: return;
1832: if (*(u_int16_t *)&sa6->sin6_addr.s6_addr[2] != 0)
1833: return;
1834: *(u_int16_t *)&sa6->sin6_addr.s6_addr[2] = htons(ifindex);
1835: }
1836: #endif
1837:
1838: int
1839: IfaceChangeAddr(Bund b, int add, struct u_range *self, struct u_addr *peer)
1840: {
1841: struct ifaliasreq ifra;
1842: struct in6_aliasreq ifra6;
1843: struct sockaddr_in *me4, *msk4, *peer4;
1844: struct sockaddr_storage ssself, sspeer, ssmsk;
1845: int res = 0;
1846: int s;
1847: char buf[48], buf1[48];
1848:
1849: Log(LG_IFACE2, ("[%s] IFACE: %s address %s->%s %s %s",
1850: b->name, add?"Add":"Remove", u_rangetoa(self, buf, sizeof(buf)),
1851: ((peer != NULL)?u_addrtoa(peer, buf1, sizeof(buf1)):""),
1852: add?"to":"from", b->iface.ifname));
1853:
1854: u_rangetosockaddrs(self, &ssself, &ssmsk);
1855: if (peer)
1856: u_addrtosockaddr(peer, 0, &sspeer);
1857:
1858: if ((s = socket(self->addr.family, SOCK_DGRAM, 0)) < 0) {
1859: Perror("[%s] IFACE: Can't get socket to change interface address", b->name);
1860: return (s);
1861: }
1862:
1863: switch (self->addr.family) {
1864: case AF_INET:
1865: memset(&ifra, '\0', sizeof(ifra));
1866: strlcpy(ifra.ifra_name, b->iface.ifname, sizeof(ifra.ifra_name));
1867:
1868: me4 = (struct sockaddr_in *)&ifra.ifra_addr;
1869: memcpy(me4, &ssself, sizeof(*me4));
1870:
1871: msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
1872: memcpy(msk4, &ssmsk, sizeof(*msk4));
1873:
1874: peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
1875: if (peer == NULL || peer->family == AF_UNSPEC) {
1876: peer4->sin_family = AF_INET;
1877: peer4->sin_len = sizeof(*peer4);
1878: peer4->sin_addr.s_addr = INADDR_NONE;
1879: } else
1880: memcpy(peer4, &sspeer, sizeof(*peer4));
1881:
1882: res = ioctl(s, add?SIOCAIFADDR:SIOCDIFADDR, &ifra);
1883: if (res == -1) {
1884: Perror("[%s] IFACE: %s IPv4 address %s %s failed",
1885: b->name, add?"Adding":"Removing", add?"to":"from", b->iface.ifname);
1886: }
1887: break;
1888:
1889: case AF_INET6:
1890: memset(&ifra6, '\0', sizeof(ifra6));
1891: strlcpy(ifra6.ifra_name, b->iface.ifname, sizeof(ifra6.ifra_name));
1892:
1893: memcpy(&ifra6.ifra_addr, &ssself, sizeof(ifra6.ifra_addr));
1894: memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof(ifra6.ifra_prefixmask));
1895: if (peer == NULL || peer->family == AF_UNSPEC)
1896: ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
1897: else if (memcmp(&((struct sockaddr_in6 *)&ssmsk)->sin6_addr, &in6mask128,
1898: sizeof(in6mask128)) == 0)
1899: memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof(ifra6.ifra_dstaddr));
1900: ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
1901: ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
1902:
1903: res = ioctl(s, add?SIOCAIFADDR_IN6:SIOCDIFADDR_IN6, &ifra6);
1904: if (res == -1) {
1905: Perror("[%s] IFACE: %s IPv6 address %s %s failed",
1906: b->name, add?"Adding":"Removing", add?"to":"from", b->iface.ifname);
1907: }
1908: break;
1909:
1910: default:
1911: res = -1;
1912: break;
1913: }
1914: close(s);
1915: return (res);
1916: }
1917:
1918: struct rtmsg {
1919: struct rt_msghdr m_rtm;
1920: char m_space[256];
1921: };
1922:
1923: static size_t
1924: memcpy_roundup(char *cp, const void *data, size_t len)
1925: {
1926: size_t padlen;
1927:
1928: #define ROUNDUP(x) ((x) ? (1 + (((x) - 1) | (sizeof(long) - 1))) : sizeof(long))
1929: padlen = ROUNDUP(len);
1930: memcpy(cp, data, len);
1931: if (padlen > len)
1932: memset(cp + len, '\0', padlen - len);
1933:
1934: return padlen;
1935: }
1936:
1937: int
1938: IfaceSetRoute(Bund b, int cmd, struct u_range *dst,
1939: struct u_addr *gw)
1940: {
1941: struct rtmsg rtmes;
1942: int s, nb, wb;
1943: char *cp;
1944: const char *cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
1945: struct sockaddr_storage sadst, samask, sagw;
1946: char buf[48], buf1[48];
1947:
1948: s = socket(PF_ROUTE, SOCK_RAW, 0);
1949: if (s < 0) {
1950: Perror("[%s] IFACE: Can't get route socket", b->name);
1951: return (-1);
1952: }
1953: memset(&rtmes, '\0', sizeof(rtmes));
1954: rtmes.m_rtm.rtm_version = RTM_VERSION;
1955: rtmes.m_rtm.rtm_type = cmd;
1956: rtmes.m_rtm.rtm_addrs = RTA_DST;
1957: rtmes.m_rtm.rtm_seq = ++gRouteSeq;
1958: rtmes.m_rtm.rtm_pid = gPid;
1959: rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
1960:
1961: u_rangetosockaddrs(dst, &sadst, &samask);
1962: #if defined(__KAME__) && !defined(NOINET6)
1963: add_scope((struct sockaddr *)&sadst, b->iface.ifindex);
1964: #endif
1965:
1966: cp = rtmes.m_space;
1967: cp += memcpy_roundup(cp, &sadst, sadst.ss_len);
1968: if (gw != NULL) {
1969: u_addrtosockaddr(gw, 0, &sagw);
1970: #if defined(__KAME__) && !defined(NOINET6)
1971: add_scope((struct sockaddr *)&sagw, b->iface.ifindex);
1972: #endif
1973: cp += memcpy_roundup(cp, &sagw, sagw.ss_len);
1974: rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
1975: } else if (cmd == RTM_ADD) {
1976: Log(LG_ERR, ("[%s] IfaceSetRoute: gw is not set\n", b->name));
1977: close(s);
1978: return (-1);
1979: }
1980:
1981: if (u_rangehost(dst)) {
1982: rtmes.m_rtm.rtm_flags |= RTF_HOST;
1983: } else {
1984: cp += memcpy_roundup(cp, &samask, samask.ss_len);
1985: rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
1986: }
1987:
1988: nb = cp - (char *)&rtmes;
1989: rtmes.m_rtm.rtm_msglen = nb;
1990: wb = write(s, &rtmes, nb);
1991: if (wb < 0) {
1992: Log(LG_ERR, ("[%s] IFACE: %s route %s %s failed: %s",
1993: b->name, cmdstr, u_rangetoa(dst, buf, sizeof(buf)),
1994: ((gw != NULL)?u_addrtoa(gw, buf1, sizeof(buf1)):""),
1995: (rtmes.m_rtm.rtm_errno != 0)?strerror(rtmes.m_rtm.rtm_errno):strerror(errno)));
1996: close(s);
1997: return (-1);
1998: }
1999: close(s);
2000: Log(LG_IFACE2, ("[%s] IFACE: %s route %s %s",
2001: b->name, cmdstr, u_rangetoa(dst, buf, sizeof(buf)),
2002: ((gw != NULL)?u_addrtoa(gw, buf1, sizeof(buf1)):"")));
2003: return (0);
2004: }
2005:
2006: #ifndef USE_NG_TCPMSS
2007: void
2008: IfaceCorrectMSS(Mbuf pkt, uint16_t maxmss)
2009: {
2010: struct ip *iphdr;
2011: struct tcphdr *tc;
2012: int pktlen, hlen, olen, optlen, accumulate;
2013: uint16_t *mss;
2014: u_char *opt;
2015:
2016: if (pkt == NULL)
2017: return;
2018:
2019: iphdr = (struct ip *)MBDATAU(pkt);
2020: hlen = iphdr->ip_hl << 2;
2021: pktlen = MBLEN(pkt) - hlen;
2022: tc = (struct tcphdr *)(MBDATAU(pkt) + hlen);
2023: hlen = tc->th_off << 2;
2024:
2025: /* Invalid header length or header without options. */
2026: if (hlen <= sizeof(struct tcphdr) || hlen > pktlen)
2027: return;
2028:
2029: /* MSS option only allowed within SYN packets. */
2030: if (!(tc->th_flags & TH_SYN))
2031: return;
2032:
2033: for (olen = hlen - sizeof(struct tcphdr), opt = (u_char *)(tc + 1);
2034: olen > 0; olen -= optlen, opt += optlen) {
2035: if (*opt == TCPOPT_EOL)
2036: break;
2037: else if (*opt == TCPOPT_NOP)
2038: optlen = 1;
2039: else {
2040: optlen = *(opt + 1);
2041: if (optlen <= 0 || optlen > olen)
2042: break;
2043: if (*opt == TCPOPT_MAXSEG) {
2044: if (optlen != TCPOLEN_MAXSEG)
2045: continue;
2046: mss = (u_int16_t *)(opt + 2);
2047: if (ntohs(*mss) > maxmss) {
2048: accumulate = *mss;
2049: *mss = htons(maxmss);
2050: accumulate -= *mss;
2051: ADJUST_CHECKSUM(accumulate, tc->th_sum);
2052: }
2053: }
2054: }
2055: }
2056: }
2057: #endif
2058:
2059: static int
2060: IfaceNgIpInit(Bund b, int ready)
2061: {
2062: struct ngm_connect cn;
2063: char path[NG_PATHSIZ];
2064: char hook[NG_HOOKSIZ];
2065:
2066: if (!ready) {
2067: /* Dial-on-Demand mode */
2068: /* Use demand hook of the socket node */
2069: snprintf(path, sizeof(path), ".:");
2070: snprintf(hook, sizeof(hook), "4%d", b->id);
2071:
2072: } else {
2073:
2074: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
2075: strcpy(hook, NG_PPP_HOOK_INET);
2076:
2077: #ifdef USE_NG_NAT
2078: /* Add a nat node if configured */
2079: if (Enabled(&b->iface.options, IFACE_CONF_NAT)) {
2080: if (IfaceInitNAT(b, path, hook))
2081: goto fail;
2082: b->iface.nat_up = 1;
2083: }
2084: #endif
2085:
2086: /* Add a tee node if configured */
2087: if (Enabled(&b->iface.options, IFACE_CONF_TEE)) {
2088: if (IfaceInitTee(b, path, hook, 0))
2089: goto fail;
2090: b->iface.tee_up = 1;
2091: }
2092:
2093: #ifdef USE_NG_IPACCT
2094: /* Connect a ipacct node if configured */
2095: if (Enabled(&b->iface.options, IFACE_CONF_IPACCT)) {
2096: if (IfaceInitIpacct(b, path, hook))
2097: goto fail;
2098: b->iface.ipacct_up = 1;
2099: }
2100: #endif /* USE_NG_IPACCT */
2101:
2102: #ifdef USE_NG_NETFLOW
2103: #ifdef NG_NETFLOW_CONF_INGRESS
2104: /* Connect a netflow node if configured */
2105: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN) ||
2106: Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) {
2107: if (IfaceInitNetflow(b, path, hook,
2108: Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)?1:0,
2109: Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)?1:0))
2110: goto fail;
2111: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN))
2112: b->iface.nfin_up = 1;
2113: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT))
2114: b->iface.nfout_up = 1;
2115: }
2116: #else /* NG_NETFLOW_CONF_INGRESS */
2117: /* Connect a netflow node if configured */
2118: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)) {
2119: if (IfaceInitNetflow(b, path, hook, 1, 0))
2120: goto fail;
2121: b->iface.nfin_up = 1;
2122: }
2123:
2124: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) {
2125: if (IfaceInitNetflow(b, path, hook, 0, 1))
2126: goto fail;
2127: b->iface.nfout_up = 1;
2128: }
2129: #endif /* NG_NETFLOW_CONF_INGRESS */
2130: #endif /* USE_NG_NETFLOW */
2131:
2132: }
2133:
2134: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
2135: if (Enabled(&b->iface.options, IFACE_CONF_TCPMSSFIX)) {
2136: if (IfaceInitMSS(b, path, hook))
2137: goto fail;
2138: b->iface.mss_up = 1;
2139: }
2140: #endif
2141:
2142: #ifdef USE_NG_BPF
2143: if (IfaceInitLimits(b, path, hook))
2144: goto fail;
2145: #endif
2146:
2147: /* Connect graph to the iface node. */
2148: memset(&cn, 0, sizeof(cn));
2149: strcpy(cn.ourhook, hook);
2150: snprintf(cn.path, sizeof(cn.path), "%s:", b->iface.ngname);
2151: strcpy(cn.peerhook, NG_IFACE_HOOK_INET);
2152: if (NgSendMsg(gLinksCsock, path,
2153: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
2154: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
2155: b->name, path, cn.ourhook, cn.path, cn.peerhook);
2156: goto fail;
2157: }
2158:
2159: if (ready) {
2160: #ifdef USE_NG_NETFLOW
2161: #ifdef NG_NETFLOW_CONF_INGRESS
2162: if (b->iface.nfin_up || b->iface.nfout_up)
2163: IfaceSetupNetflow(b, b->iface.nfin_up, b->iface.nfout_up);
2164: #else /* NG_NETFLOW_CONF_INGRESS */
2165: if (b->iface.nfin_up)
2166: IfaceSetupNetflow(b, 1, 0);
2167:
2168: if (b->iface.nfout_up)
2169: IfaceSetupNetflow(b, 0, 1);
2170: #endif /* NG_NETFLOW_CONF_INGRESS */
2171: #endif /* USE_NG_NETFLOW */
2172: }
2173:
2174: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
2175: if (b->iface.mss_up)
2176: IfaceSetupMSS(b, MAXMSS(b->iface.mtu));
2177: #endif
2178:
2179: #ifdef USE_NG_BPF
2180: IfaceSetupLimits(b);
2181: #endif
2182:
2183: /* OK */
2184: return(0);
2185:
2186: fail:
2187: return(-1);
2188: }
2189:
2190: /*
2191: * IfaceNgIpShutdown()
2192: */
2193:
2194: static void
2195: IfaceNgIpShutdown(Bund b)
2196: {
2197: char path[NG_PATHSIZ];
2198:
2199: #ifdef USE_NG_BPF
2200: IfaceShutdownLimits(b); /* Limits must shutdown first to save final stats. */
2201: #endif
2202: #ifdef USE_NG_NAT
2203: if (b->iface.nat_up)
2204: IfaceShutdownNAT(b);
2205: b->iface.nat_up = 0;
2206: #endif
2207: if (b->iface.tee_up)
2208: IfaceShutdownTee(b, 0);
2209: b->iface.tee_up = 0;
2210: #ifdef USE_NG_NETFLOW
2211: #ifdef NG_NETFLOW_CONF_INGRESS
2212: if (b->iface.nfin_up || b->iface.nfout_up)
2213: IfaceShutdownNetflow(b, b->iface.nfin_up, b->iface.nfout_up);
2214: b->iface.nfin_up = 0;
2215: b->iface.nfout_up = 0;
2216: #else /* NG_NETFLOW_CONF_INGRESS */
2217: if (b->iface.nfin_up)
2218: IfaceShutdownNetflow(b, 1, 0);
2219: b->iface.nfin_up = 0;
2220: if (b->iface.nfout_up)
2221: IfaceShutdownNetflow(b, 0, 1);
2222: b->iface.nfout_up = 0;
2223: #endif /* NG_NETFLOW_CONF_INGRESS */
2224: #endif
2225: #ifdef USE_NG_IPACCT
2226: if (b->iface.ipacct_up)
2227: IfaceShutdownIpacct(b);
2228: b->iface.ipacct_up = 0;
2229: #endif
2230: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
2231: if (b->iface.mss_up)
2232: IfaceShutdownMSS(b);
2233: #endif
2234: b->iface.mss_up = 0;
2235:
2236: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
2237: NgFuncDisconnect(gLinksCsock, b->name, path, NG_PPP_HOOK_INET);
2238:
2239: snprintf(path, sizeof(path), "%s:", b->iface.ngname);
2240: NgFuncDisconnect(gLinksCsock, b->name, path, NG_IFACE_HOOK_INET);
2241: }
2242:
2243: static int
2244: IfaceNgIpv6Init(Bund b, int ready)
2245: {
2246: struct ngm_connect cn;
2247: char path[NG_PATHSIZ];
2248: char hook[NG_HOOKSIZ];
2249:
2250: if (!ready) {
2251: /* Dial-on-Demand mode */
2252: /* Use demand hook of the socket node */
2253: snprintf(path, sizeof(path), ".:");
2254: snprintf(hook, sizeof(hook), "6%d", b->id);
2255: } else {
2256: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
2257: strcpy(hook, NG_PPP_HOOK_IPV6);
2258:
2259: /* Add a tee node if configured */
2260: if (Enabled(&b->iface.options, IFACE_CONF_TEE)) {
2261: if (IfaceInitTee(b, path, hook, 1))
2262: goto fail;
2263: b->iface.tee6_up = 1;
2264: }
2265:
2266: }
2267:
2268: /* Connect graph to the iface node. */
2269: strcpy(cn.ourhook, hook);
2270: snprintf(cn.path, sizeof(cn.path), "%s:", b->iface.ngname);
2271: strcpy(cn.peerhook, NG_IFACE_HOOK_INET6);
2272: if (NgSendMsg(gLinksCsock, path,
2273: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
2274: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
2275: b->name, path, cn.ourhook, cn.path, cn.peerhook);
2276: goto fail;
2277: }
2278:
2279: /* OK */
2280: return(0);
2281:
2282: fail:
2283: return(-1);
2284: }
2285:
2286: /*
2287: * IfaceNgIpv6Shutdown()
2288: */
2289:
2290: static void
2291: IfaceNgIpv6Shutdown(Bund b)
2292: {
2293: char path[NG_PATHSIZ];
2294:
2295: if (b->iface.tee6_up)
2296: IfaceShutdownTee(b, 1);
2297: b->iface.tee6_up = 0;
2298:
2299: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
2300: NgFuncDisconnect(gLinksCsock, b->name, path, NG_PPP_HOOK_IPV6);
2301:
2302: snprintf(path, sizeof(path), "%s:", b->iface.ngname);
2303: NgFuncDisconnect(gLinksCsock, b->name, path, NG_IFACE_HOOK_INET6);
2304: }
2305:
2306: #ifdef USE_NG_NAT
2307: static int
2308: IfaceInitNAT(Bund b, char *path, char *hook)
2309: {
2310: NatState const nat = &b->iface.nat;
2311: struct ngm_mkpeer mp;
2312: struct ngm_name nm;
2313: struct in_addr ip;
2314: #ifdef NG_NAT_LOG
2315: struct ng_nat_mode mode;
2316: #endif
2317: Log(LG_IFACE2, ("[%s] IFACE: Connecting NAT", b->name));
2318:
2319: strcpy(mp.type, NG_NAT_NODE_TYPE);
2320: strcpy(mp.ourhook, hook);
2321: strcpy(mp.peerhook, NG_NAT_HOOK_IN);
2322: if (NgSendMsg(gLinksCsock, path,
2323: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2324: Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
2325: b->name, NG_NAT_NODE_TYPE, path, mp.ourhook);
2326: return(-1);
2327: }
2328: strlcat(path, ".", NG_PATHSIZ);
2329: strlcat(path, hook, NG_PATHSIZ);
2330: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-nat", gPid, b->name);
2331: if (NgSendMsg(gLinksCsock, path,
2332: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2333: Perror("[%s] can't name %s node", b->name, NG_NAT_NODE_TYPE);
2334: return(-1);
2335: }
2336: strcpy(hook, NG_NAT_HOOK_OUT);
2337:
2338: /* Set NAT IP */
2339: if (u_addrempty(&nat->alias_addr)) {
2340: ip.s_addr = 1; // Set something just to make it ready
2341: } else {
2342: ip = nat->alias_addr.u.ip4;
2343: }
2344: if (NgSendMsg(gLinksCsock, path,
2345: NGM_NAT_COOKIE, NGM_NAT_SET_IPADDR, &ip, sizeof(ip)) < 0)
2346: Perror("[%s] can't set NAT ip", b->name);
2347:
2348: #ifdef NG_NAT_LOG
2349: /* Set NAT mode */
2350: mode.flags = 0;
2351: if (Enabled(&nat->options, NAT_CONF_LOG))
2352: mode.flags |= NG_NAT_LOG;
2353: if (!Enabled(&nat->options, NAT_CONF_INCOMING))
2354: mode.flags |= NG_NAT_DENY_INCOMING;
2355: if (Enabled(&nat->options, NAT_CONF_SAME_PORTS))
2356: mode.flags |= NG_NAT_SAME_PORTS;
2357: if (Enabled(&nat->options, NAT_CONF_UNREG_ONLY))
2358: mode.flags |= NG_NAT_UNREGISTERED_ONLY;
2359:
2360: mode.mask = NG_NAT_LOG | NG_NAT_DENY_INCOMING |
2361: NG_NAT_SAME_PORTS | NG_NAT_UNREGISTERED_ONLY;
2362: if (NgSendMsg(gLinksCsock, path,
2363: NGM_NAT_COOKIE, NGM_NAT_SET_MODE, &mode, sizeof(mode)) < 0)
2364: Perror("[%s] can't set NAT mode", b->name);
2365:
2366: /* Set NAT target IP */
2367: if (!u_addrempty(&nat->target_addr)) {
2368: ip = nat->target_addr.u.ip4;
2369: if (NgSendMsg(gLinksCsock, path,
2370: NGM_NAT_COOKIE, NGM_NAT_SET_IPADDR, &ip, sizeof(ip)) < 0) {
2371: Perror("[%s] can't set NAT target IP", b->name);
2372: }
2373: }
2374: #endif
2375:
2376: return(0);
2377: }
2378:
2379: static int
2380: IfaceSetupNAT(Bund b)
2381: {
2382: NatState const nat = &b->iface.nat;
2383: char path[NG_PATHSIZ];
2384: int k;
2385:
2386: if (u_addrempty(&nat->alias_addr)) {
2387: snprintf(path, sizeof(path), "mpd%d-%s-nat:", gPid, b->name);
2388: if (NgSendMsg(gLinksCsock, path,
2389: NGM_NAT_COOKIE, NGM_NAT_SET_IPADDR,
2390: &b->iface.self_addr.addr.u.ip4,
2391: sizeof(b->iface.self_addr.addr.u.ip4)) < 0) {
2392: Perror("[%s] can't set NAT ip", b->name);
2393: return (-1);
2394: }
2395: }
2396: #ifdef NG_NAT_DESC_LENGTH
2397: /* redirect-port */
2398: for(k = 0; k < NM_PORT; k++) {
2399: if(nat->nrpt_id[k]) {
2400: if (NgSendMsg(gLinksCsock, path,
2401: NGM_NAT_COOKIE, NGM_NAT_REDIRECT_PORT, &nat->nrpt[k],
2402: sizeof(struct ng_nat_redirect_port)) < 0) {
2403: Perror("[%s] can't set NAT redirect-port", b->name);
2404: }
2405: }
2406: }
2407: /* redirect-addr */
2408: for(k = 0; k < NM_ADDR; k++) {
2409: if(nat->nrad_id[k]) {
2410: if (NgSendMsg(gLinksCsock, path,
2411: NGM_NAT_COOKIE, NGM_NAT_REDIRECT_ADDR, &nat->nrad[k],
2412: sizeof(struct ng_nat_redirect_addr)) < 0) {
2413: Perror("[%s] can't set NAT redirect-addr", b->name);
2414: }
2415: }
2416: }
2417: /* redirect-proto */
2418: for(k = 0; k < NM_PROTO; k++) {
2419: if(nat->nrpr_id[k]) {
2420: if (NgSendMsg(gLinksCsock, path,
2421: NGM_NAT_COOKIE, NGM_NAT_REDIRECT_PROTO, &nat->nrpr[k],
2422: sizeof(struct ng_nat_redirect_proto)) < 0) {
2423: Perror("[%s] can't set NAT redirect-proto", b->name);
2424: }
2425: }
2426: }
2427: #endif
2428: return (0);
2429: }
2430:
2431: static void
2432: IfaceShutdownNAT(Bund b)
2433: {
2434: char path[NG_PATHSIZ];
2435:
2436: snprintf(path, sizeof(path), "mpd%d-%s-nat:", gPid, b->name);
2437: NgFuncShutdownNode(gLinksCsock, b->name, path);
2438: }
2439: #endif /* USE_NG_NAT */
2440:
2441: static int
2442: IfaceInitTee(Bund b, char *path, char *hook, int v6)
2443: {
2444: struct ngm_mkpeer mp;
2445: struct ngm_name nm;
2446:
2447: Log(LG_IFACE2, ("[%s] IFACE: Connecting tee%s", b->name, v6?"6":""));
2448:
2449: strcpy(mp.type, NG_TEE_NODE_TYPE);
2450: strcpy(mp.ourhook, hook);
2451: strcpy(mp.peerhook, NG_TEE_HOOK_RIGHT);
2452: if (NgSendMsg(gLinksCsock, path,
2453: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2454: Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
2455: b->name, NG_TEE_NODE_TYPE, path, mp.ourhook);
2456: return(-1);
2457: }
2458: strlcat(path, ".", NG_PATHSIZ);
2459: strlcat(path, hook, NG_PATHSIZ);
2460: snprintf(nm.name, sizeof(nm.name), "%s-tee%s", b->iface.ifname, v6?"6":"");
2461: if (NgSendMsg(gLinksCsock, path,
2462: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2463: Perror("[%s] can't name %s node", b->name, NG_TEE_NODE_TYPE);
2464: return(-1);
2465: }
2466: strcpy(hook, NG_TEE_HOOK_LEFT);
2467:
2468: return(0);
2469: }
2470:
2471: static void
2472: IfaceShutdownTee(Bund b, int v6)
2473: {
2474: char path[NG_PATHSIZ];
2475:
2476: snprintf(path, sizeof(path), "%s-tee%s:", b->iface.ifname, v6?"6":"");
2477: NgFuncShutdownNode(gLinksCsock, b->name, path);
2478: }
2479:
2480: #ifdef USE_NG_IPACCT
2481: static int
2482: IfaceInitIpacct(Bund b, char *path, char *hook)
2483: {
2484: struct ngm_mkpeer mp;
2485: struct ngm_name nm;
2486: struct ngm_connect cn;
2487: char path1[NG_PATHSIZ];
2488: struct {
2489: struct ng_ipacct_mesg m;
2490: int data;
2491: } ipam;
2492:
2493: Log(LG_IFACE2, ("[%s] IFACE: Connecting ipacct", b->name));
2494:
2495: strcpy(mp.type, NG_TEE_NODE_TYPE);
2496: strcpy(mp.ourhook, hook);
2497: strcpy(mp.peerhook, NG_TEE_HOOK_RIGHT);
2498: if (NgSendMsg(gLinksCsock, path,
2499: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2500: Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
2501: b->name, NG_TEE_NODE_TYPE, path, mp.ourhook);
2502: return(-1);
2503: }
2504: strlcat(path, ".", NG_PATHSIZ);
2505: strlcat(path, hook, NG_PATHSIZ);
2506: snprintf(nm.name, sizeof(nm.name), "%s_acct_tee", b->iface.ifname);
2507: if (NgSendMsg(gLinksCsock, path,
2508: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2509: Perror("[%s] can't name %s node", b->name, NG_TEE_NODE_TYPE);
2510: return(-1);
2511: }
2512: strcpy(hook, NG_TEE_HOOK_LEFT);
2513:
2514: strcpy(mp.type, NG_IPACCT_NODE_TYPE);
2515: strcpy(mp.ourhook, NG_TEE_HOOK_RIGHT2LEFT);
2516: snprintf(mp.peerhook, sizeof(mp.peerhook), "%s_in", b->iface.ifname);
2517: if (NgSendMsg(gLinksCsock, path,
2518: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2519: Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
2520: b->name, NG_IPACCT_NODE_TYPE, path, mp.ourhook);
2521: return(-1);
2522: }
2523: snprintf(path1, sizeof(path1), "%s.%s", path, NG_TEE_HOOK_RIGHT2LEFT);
2524: snprintf(nm.name, sizeof(nm.name), "%s_ip_acct", b->iface.ifname);
2525: if (NgSendMsg(gLinksCsock, path1,
2526: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2527: Perror("[%s] can't name %s node", b->name, NG_IPACCT_NODE_TYPE);
2528: return(-1);
2529: }
2530: strcpy(cn.ourhook, NG_TEE_HOOK_LEFT2RIGHT);
2531: strcpy(cn.path, NG_TEE_HOOK_RIGHT2LEFT);
2532: snprintf(cn.peerhook, sizeof(cn.peerhook), "%s_out", b->iface.ifname);
2533: if (NgSendMsg(gLinksCsock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
2534: sizeof(cn)) < 0) {
2535: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
2536: b->name, path, cn.ourhook, cn.path, cn.peerhook);
2537: return (-1);
2538: }
2539:
2540: snprintf(ipam.m.hname, sizeof(ipam.m.hname), "%s_in", b->iface.ifname);
2541: ipam.data = DLT_RAW;
2542: if (NgSendMsg(gLinksCsock, path1, NGM_IPACCT_COOKIE, NGM_IPACCT_SETDLT,
2543: &ipam, sizeof(ipam)) < 0) {
2544: Perror("[%s] can't set DLT \"%s\"->\"%s\"", b->name, path, ipam.m.hname);
2545: return (-1);
2546: }
2547: ipam.data = 10000;
2548: if (NgSendMsg(gLinksCsock, path1, NGM_IPACCT_COOKIE, NGM_IPACCT_STHRS,
2549: &ipam, sizeof(ipam)) < 0) {
2550: Perror("[%s] can't set DLT \"%s\"->\"%s\"", b->name, path, ipam.m.hname);
2551: return (-1);
2552: }
2553:
2554: snprintf(ipam.m.hname, sizeof(ipam.m.hname), "%s_out", b->iface.ifname);
2555: ipam.data = DLT_RAW;
2556: if (NgSendMsg(gLinksCsock, path1, NGM_IPACCT_COOKIE, NGM_IPACCT_SETDLT,
2557: &ipam, sizeof(ipam)) < 0) {
2558: Perror("[%s] can't set DLT \"%s\"->\"%s\"", b->name, path, ipam.m.hname);
2559: return (-1);
2560: }
2561: ipam.data = 10000;
2562: if (NgSendMsg(gLinksCsock, path1, NGM_IPACCT_COOKIE, NGM_IPACCT_STHRS,
2563: &ipam, sizeof(ipam)) < 0) {
2564: Perror("[%s] can't set DLT \"%s\"->\"%s\"", b->name, path, ipam.m.hname);
2565: return (-1);
2566: }
2567:
2568: return(0);
2569: }
2570:
2571: static void
2572: IfaceShutdownIpacct(Bund b)
2573: {
2574: char path[NG_PATHSIZ];
2575:
2576: snprintf(path, sizeof(path), "%s_acct_tee:", b->iface.ifname);
2577: NgFuncShutdownNode(gLinksCsock, b->name, path);
2578: }
2579: #endif
2580:
2581: #ifdef USE_NG_NETFLOW
2582: static int
2583: IfaceInitNetflow(Bund b, char *path, char *hook, char in, char out)
2584: {
2585: struct ngm_connect cn;
2586: int nif;
2587:
2588: #ifdef NG_NETFLOW_CONF_INGRESS
2589: nif = gNetflowIface + b->id;
2590: #else
2591: nif = gNetflowIface + b->id*2 + out;
2592: #endif
2593:
2594: Log(LG_IFACE2, ("[%s] IFACE: Connecting netflow (%s)", b->name, out?"out":"in"));
2595:
2596: /* Create global ng_netflow(4) node if not yet. */
2597: if (gNetflowNodeID == 0) {
2598: if (NgFuncInitGlobalNetflow())
2599: return(-1);
2600: }
2601:
2602: /* Connect ng_netflow(4) node to the ng_bpf(4)/ng_tee(4) node. */
2603: strcpy(cn.ourhook, hook);
2604: snprintf(cn.path, sizeof(cn.path), "[%x]:", gNetflowNodeID);
2605: #ifndef NG_NETFLOW_CONF_INGRESS
2606: if (out) {
2607: snprintf(cn.peerhook, sizeof(cn.peerhook), "%s%d", NG_NETFLOW_HOOK_OUT,
2608: nif);
2609: } else {
2610: #endif
2611: snprintf(cn.peerhook, sizeof(cn.peerhook), "%s%d", NG_NETFLOW_HOOK_DATA,
2612: nif);
2613: #ifndef NG_NETFLOW_CONF_INGRESS
2614: }
2615: #endif
2616: if (NgSendMsg(gLinksCsock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
2617: sizeof(cn)) < 0) {
2618: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
2619: b->name, path, cn.ourhook, cn.path, cn.peerhook);
2620: return (-1);
2621: }
2622: strlcat(path, ".", NG_PATHSIZ);
2623: strlcat(path, hook, NG_PATHSIZ);
2624: #ifndef NG_NETFLOW_CONF_INGRESS
2625: if (out) {
2626: snprintf(hook, NG_HOOKSIZ, "%s%d", NG_NETFLOW_HOOK_DATA, nif);
2627: } else {
2628: #endif
2629: snprintf(hook, NG_HOOKSIZ, "%s%d", NG_NETFLOW_HOOK_OUT, nif);
2630: #ifndef NG_NETFLOW_CONF_INGRESS
2631: }
2632: #endif
2633: return (0);
2634: }
2635:
2636: static int
2637: IfaceSetupNetflow(Bund b, char in, char out)
2638: {
2639: char path[NG_PATHSIZ];
2640: struct ng_netflow_setdlt nf_setdlt;
2641: struct ng_netflow_setifindex nf_setidx;
2642: #ifdef NG_NETFLOW_CONF_INGRESS
2643: struct ng_netflow_setconfig nf_setconf;
2644: #endif
2645: int nif;
2646:
2647: #ifdef NG_NETFLOW_CONF_INGRESS
2648: nif = gNetflowIface + b->id;
2649: #else
2650: nif = gNetflowIface + b->id*2 + out;
2651: #endif
2652:
2653: /* Configure data link type and interface index. */
2654: snprintf(path, sizeof(path), "[%x]:", gNetflowNodeID);
2655: nf_setdlt.iface = nif;
2656: nf_setdlt.dlt = DLT_RAW;
2657: if (NgSendMsg(gLinksCsock, path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_SETDLT,
2658: &nf_setdlt, sizeof(nf_setdlt)) < 0) {
2659: Perror("[%s] can't configure data link type on %s", b->name, path);
2660: goto fail;
2661: }
2662: #ifdef NG_NETFLOW_CONF_INGRESS
2663: nf_setconf.iface = nif;
2664: nf_setconf.conf =
2665: (in?NG_NETFLOW_CONF_INGRESS:0) |
2666: (out?NG_NETFLOW_CONF_EGRESS:0) |
2667: (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_ONCE)?NG_NETFLOW_CONF_ONCE:0);
2668: if (NgSendMsg(gLinksCsock, path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_SETCONFIG,
2669: &nf_setconf, sizeof(nf_setconf)) < 0) {
2670: Perror("[%s] can't set config on %s", b->name, path);
2671: goto fail;
2672: }
2673: #endif
2674: #ifndef NG_NETFLOW_CONF_INGRESS
2675: if (!out) {
2676: #endif
2677: nf_setidx.iface = nif;
2678: nf_setidx.index = if_nametoindex(b->iface.ifname);
2679: if (NgSendMsg(gLinksCsock, path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_SETIFINDEX,
2680: &nf_setidx, sizeof(nf_setidx)) < 0) {
2681: Perror("[%s] can't configure interface index on %s", b->name, path);
2682: goto fail;
2683: }
2684: #ifndef NG_NETFLOW_CONF_INGRESS
2685: }
2686: #endif
2687:
2688: return 0;
2689: fail:
2690: return -1;
2691: }
2692:
2693: static void
2694: IfaceShutdownNetflow(Bund b, char in, char out)
2695: {
2696: char path[NG_PATHSIZ];
2697: char hook[NG_HOOKSIZ];
2698: int nif;
2699:
2700: #ifdef NG_NETFLOW_CONF_INGRESS
2701: nif = gNetflowIface + b->id;
2702: #else
2703: nif = gNetflowIface + b->id*2 + out;
2704: #endif
2705:
2706: snprintf(path, NG_PATHSIZ, "[%x]:", gNetflowNodeID);
2707: snprintf(hook, NG_HOOKSIZ, "%s%d", NG_NETFLOW_HOOK_DATA, nif);
2708: NgFuncDisconnect(gLinksCsock, b->name, path, hook);
2709: snprintf(hook, NG_HOOKSIZ, "%s%d", NG_NETFLOW_HOOK_OUT, nif);
2710: NgFuncDisconnect(gLinksCsock, b->name, path, hook);
2711: }
2712: #endif
2713:
2714: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
2715: static int
2716: IfaceInitMSS(Bund b, char *path, char *hook)
2717: {
2718: struct ngm_mkpeer mp;
2719: struct ngm_name nm;
2720: #ifndef USE_NG_TCPMSS
2721: struct ngm_connect cn;
2722: #endif
2723:
2724: Log(LG_IFACE2, ("[%s] IFACE: Connecting tcpmssfix", b->name));
2725:
2726: #ifdef USE_NG_TCPMSS
2727: /* Create ng_tcpmss(4) node. */
2728: strcpy(mp.type, NG_TCPMSS_NODE_TYPE);
2729: strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
2730: strcpy(mp.peerhook, "in");
2731: if (NgSendMsg(gLinksCsock, path,
2732: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2733: Perror("can't create %s node at \"%s\"->\"%s\"",
2734: NG_TCPMSS_NODE_TYPE, path, mp.ourhook);
2735: goto fail;
2736: }
2737:
2738: strlcat(path, ".", NG_PATHSIZ);
2739: strlcat(path, hook, NG_PATHSIZ);
2740: snprintf(hook, NG_HOOKSIZ, "out");
2741:
2742: /* Set the new node's name. */
2743: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-mss", gPid, b->name);
2744: if (NgSendMsg(gLinksCsock, path,
2745: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2746: Perror("can't name %s node", NG_TCPMSS_NODE_TYPE);
2747: goto fail;
2748: }
2749:
2750: #else
2751: /* Create a bpf node for SYN detection. */
2752: strcpy(mp.type, NG_BPF_NODE_TYPE);
2753: strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
2754: strcpy(mp.peerhook, "ppp");
2755: if (NgSendMsg(gLinksCsock, path,
2756: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2757: Perror("can't create %s node at \"%s\"->\"%s\"",
2758: NG_BPF_NODE_TYPE, path, mp.ourhook);
2759: goto fail;
2760: }
2761:
2762: strlcat(path, ".", NG_PATHSIZ);
2763: strlcat(path, hook, NG_PATHSIZ);
2764: strcpy(hook, "iface");
2765:
2766: /* Set the new node's name. */
2767: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-mss", gPid, b->name);
2768: if (NgSendMsg(gLinksCsock, path,
2769: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2770: Perror("can't name tcpmssfix %s node", NG_BPF_NODE_TYPE);
2771: goto fail;
2772: }
2773:
2774: /* Connect to the bundle socket node. */
2775: strlcpy(cn.path, path, sizeof(cn.path));
2776: snprintf(cn.ourhook, sizeof(cn.ourhook), "i%d", b->id);
2777: strcpy(cn.peerhook, MPD_HOOK_TCPMSS_IN);
2778: if (NgSendMsg(gLinksCsock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
2779: sizeof(cn)) < 0) {
2780: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
2781: b->name, path, cn.ourhook, cn.path, cn.peerhook);
2782: goto fail;
2783: }
2784:
2785: strlcpy(cn.path, path, sizeof(cn.path));
2786: snprintf(cn.ourhook, sizeof(cn.ourhook), "o%d", b->id);
2787: strcpy(cn.peerhook, MPD_HOOK_TCPMSS_OUT);
2788: if (NgSendMsg(gLinksCsock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
2789: sizeof(cn)) < 0) {
2790: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
2791: b->name, path, cn.ourhook, cn.path, cn.peerhook);
2792: goto fail;
2793: }
2794: #endif /* USE_NG_TCPMSS */
2795:
2796: return (0);
2797: fail:
2798: return (-1);
2799: }
2800:
2801: /*
2802: * BundConfigMSS()
2803: *
2804: * Configure the tcpmss node to reduce MSS to given value.
2805: */
2806:
2807: static void
2808: IfaceSetupMSS(Bund b, uint16_t maxMSS)
2809: {
2810: #ifdef USE_NG_TCPMSS
2811: struct ng_tcpmss_config tcpmsscfg;
2812: char path[NG_PATHSIZ];
2813:
2814: snprintf(path, sizeof(path), "mpd%d-%s-mss:", gPid, b->name);
2815:
2816: /* Send configure message. */
2817: memset(&tcpmsscfg, 0, sizeof(tcpmsscfg));
2818: tcpmsscfg.maxMSS = maxMSS;
2819:
2820: snprintf(tcpmsscfg.inHook, sizeof(tcpmsscfg.inHook), "in");
2821: snprintf(tcpmsscfg.outHook, sizeof(tcpmsscfg.outHook), "out");
2822: if (NgSendMsg(gLinksCsock, path, NGM_TCPMSS_COOKIE, NGM_TCPMSS_CONFIG,
2823: &tcpmsscfg, sizeof(tcpmsscfg)) < 0) {
2824: Perror("[%s] can't configure %s node program", b->name, NG_TCPMSS_NODE_TYPE);
2825: }
2826: snprintf(tcpmsscfg.inHook, sizeof(tcpmsscfg.inHook), "out");
2827: snprintf(tcpmsscfg.outHook, sizeof(tcpmsscfg.outHook), "in");
2828: if (NgSendMsg(gLinksCsock, path, NGM_TCPMSS_COOKIE, NGM_TCPMSS_CONFIG,
2829: &tcpmsscfg, sizeof(tcpmsscfg)) < 0) {
2830: Perror("[%s] can't configure %s node program", b->name, NG_TCPMSS_NODE_TYPE);
2831: }
2832: #else
2833: union {
2834: u_char buf[NG_BPF_HOOKPROG_SIZE(TCPSYN_PROG_LEN)];
2835: struct ng_bpf_hookprog hprog;
2836: } u;
2837: struct ng_bpf_hookprog *const hp = &u.hprog;
2838: char hook[NG_HOOKSIZ];
2839:
2840: /* Setup programs for ng_bpf hooks */
2841: snprintf(hook, sizeof(hook), "i%d", b->id);
2842:
2843: memset(&u, 0, sizeof(u));
2844: strcpy(hp->thisHook, "ppp");
2845: hp->bpf_prog_len = TCPSYN_PROG_LEN;
2846: memcpy(&hp->bpf_prog, &gTCPSYNProg,
2847: TCPSYN_PROG_LEN * sizeof(*gTCPSYNProg));
2848: strcpy(hp->ifMatch, MPD_HOOK_TCPMSS_IN);
2849: strcpy(hp->ifNotMatch, "iface");
2850:
2851: if (NgSendMsg(gLinksCsock, hook, NGM_BPF_COOKIE,
2852: NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0)
2853: Perror("[%s] can't set %s node program", b->name, NG_BPF_NODE_TYPE);
2854:
2855: memset(&u, 0, sizeof(u));
2856: strcpy(hp->thisHook, MPD_HOOK_TCPMSS_IN);
2857: hp->bpf_prog_len = NOMATCH_PROG_LEN;
2858: memcpy(&hp->bpf_prog, &gNoMatchProg,
2859: NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
2860: strcpy(hp->ifMatch, "ppp");
2861: strcpy(hp->ifNotMatch, "ppp");
2862:
2863: if (NgSendMsg(gLinksCsock, hook, NGM_BPF_COOKIE,
2864: NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0)
2865: Perror("[%s] can't set %s node program", b->name, NG_BPF_NODE_TYPE);
2866:
2867: snprintf(hook, sizeof(hook), "o%d", b->id);
2868: memset(&u, 0, sizeof(u));
2869: strcpy(hp->thisHook, "iface");
2870: hp->bpf_prog_len = TCPSYN_PROG_LEN;
2871: memcpy(&hp->bpf_prog, &gTCPSYNProg,
2872: TCPSYN_PROG_LEN * sizeof(*gTCPSYNProg));
2873: strcpy(hp->ifMatch, MPD_HOOK_TCPMSS_OUT);
2874: strcpy(hp->ifNotMatch, "ppp");
2875:
2876: if (NgSendMsg(gLinksCsock, hook, NGM_BPF_COOKIE,
2877: NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0)
2878: Perror("[%s] can't set %s node program", b->name, NG_BPF_NODE_TYPE);
2879:
2880: memset(&u, 0, sizeof(u));
2881: strcpy(hp->thisHook, MPD_HOOK_TCPMSS_OUT);
2882: hp->bpf_prog_len = NOMATCH_PROG_LEN;
2883: memcpy(&hp->bpf_prog, &gNoMatchProg,
2884: NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
2885: strcpy(hp->ifMatch, "iface");
2886: strcpy(hp->ifNotMatch, "iface");
2887:
2888: if (NgSendMsg(gLinksCsock, hook, NGM_BPF_COOKIE,
2889: NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0)
2890: Perror("[%s] can't set %s node program", b->name, NG_BPF_NODE_TYPE);
2891:
2892: #endif /* USE_NG_TCPMSS */
2893: }
2894:
2895: static void
2896: IfaceShutdownMSS(Bund b)
2897: {
2898: char path[NG_PATHSIZ];
2899:
2900: #ifdef USE_NG_TCPMSS
2901: snprintf(path, sizeof(path), "mpd%d-%s-mss:", gPid, b->name);
2902: NgFuncShutdownNode(gLinksCsock, b->name, path);
2903: #else
2904: snprintf(path, sizeof(path), "i%d", b->id);
2905: NgFuncShutdownNode(gLinksCsock, b->name, path);
2906: #endif
2907: }
2908: #endif /* defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF)) */
2909:
2910: #ifdef USE_NG_BPF
2911: static int
2912: IfaceInitLimits(Bund b, char *path, char *hook)
2913: {
2914: struct ngm_mkpeer mp;
2915: struct ngm_name nm;
2916:
2917: if (b->params.acl_limits[0] || b->params.acl_limits[1]) {
2918:
2919: Log(LG_IFACE2, ("[%s] IFACE: Connecting limits", b->name));
2920:
2921: /* Create a bpf node for traffic filtering. */
2922: strcpy(mp.type, NG_BPF_NODE_TYPE);
2923: strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
2924: strcpy(mp.peerhook, "ppp");
2925: if (NgSendMsg(gLinksCsock, path,
2926: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2927: Perror("can't create %s node at \"%s\"->\"%s\"",
2928: NG_BPF_NODE_TYPE, path, mp.ourhook);
2929: goto fail;
2930: }
2931:
2932: strlcat(path, ".", NG_PATHSIZ);
2933: strlcat(path, hook, NG_PATHSIZ);
2934: strcpy(hook, "iface");
2935:
2936: b->iface.limitID = NgGetNodeID(gLinksCsock, path);
2937: if (b->iface.limitID == 0)
2938: Perror("can't get limits %s node ID", NG_BPF_NODE_TYPE);
2939:
2940: /* Set the new node's name. */
2941: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-lim", gPid, b->name);
2942: if (NgSendMsg(gLinksCsock, path,
2943: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2944: Perror("can't name limits %s node", NG_BPF_NODE_TYPE);
2945: goto fail;
2946: }
2947:
2948: }
2949:
2950: return (0);
2951: fail:
2952: return (-1);
2953: }
2954:
2955: /*
2956: * BundConfigLimits()
2957: *
2958: * Configure the bpf & car nodes.
2959: */
2960:
2961: static void
2962: IfaceSetupLimits(Bund b)
2963: {
2964: #define ACL_MAX_PROGLEN 65536
2965: union {
2966: u_char buf[NG_BPF_HOOKPROG_SIZE(ACL_MAX_PROGLEN)];
2967: struct ng_bpf_hookprog hprog;
2968: } *hpu;
2969: struct ng_bpf_hookprog *hp;
2970: struct ngm_connect cn;
2971: int i;
2972:
2973: hpu = Malloc(MB_IFACE, sizeof(*hpu));
2974: hp = &hpu->hprog;
2975:
2976: if (b->params.acl_limits[0] || b->params.acl_limits[1]) {
2977: char path[NG_PATHSIZ];
2978: int num, dir;
2979:
2980: snprintf(path, sizeof(path), "mpd%d-%s-lim:", gPid, b->name);
2981:
2982: for (dir = 0; dir < 2; dir++) {
2983: char inhook[2][NG_HOOKSIZ];
2984: char inhookn[2][NG_HOOKSIZ];
2985: char outhook[NG_HOOKSIZ];
2986: struct acl *l;
2987:
2988: if (dir == 0) {
2989: strcpy(inhook[0], "ppp");
2990: strcpy(outhook, "iface");
2991: } else {
2992: strcpy(inhook[0], "iface");
2993: strcpy(outhook, "ppp");
2994: }
2995: strcpy(inhook[1], "");
2996: num = 0;
2997: for (l = b->params.acl_limits[dir]; l; l = l->next) {
2998: char str[ACL_LEN];
2999: #define ACL_MAX_PARAMS 7 /* one more then max number of arguments */
3000: int ac;
3001: char *av[ACL_MAX_PARAMS];
3002: int p;
3003: char stathook[NG_HOOKSIZ];
3004: struct svcs *ss = NULL;
3005: struct svcssrc *sss = NULL;
3006:
3007: Log(LG_IFACE2, ("[%s] IFACE: limit %s#%d%s%s: '%s'",
3008: b->name, (dir?"out":"in"), l->number,
3009: ((l->name[0])?"#":""), l->name, l->rule));
3010: strlcpy(str, l->rule, sizeof(str));
3011: ac = ParseLine(str, av, ACL_MAX_PARAMS, 0);
3012: if (ac < 1 || ac >= ACL_MAX_PARAMS) {
3013: Log(LG_ERR, ("[%s] IFACE: incorrect limit: '%s'",
3014: b->name, l->rule));
3015: continue;
3016: }
3017:
3018: stathook[0] = 0;
3019: memset(hpu, 0, sizeof(hpu));
3020: /* Prepare filter */
3021: if (strcasecmp(av[0], "all") == 0) {
3022: hp->bpf_prog_len = MATCH_PROG_LEN;
3023: memcpy(&hp->bpf_prog, &gMatchProg,
3024: MATCH_PROG_LEN * sizeof(*gMatchProg));
3025: } else if (strncasecmp(av[0], "flt", 3) == 0) {
3026: struct acl *f;
3027: int flt;
3028:
3029: flt = atoi(av[0] + 3);
3030: if (flt <= 0 || flt > ACL_FILTERS) {
3031: Log(LG_ERR, ("[%s] IFACE: incorrect filter number: '%s'",
3032: b->name, av[0]));
3033: } else if ((f = b->params.acl_filters[flt - 1]) == NULL &&
3034: (f = acl_filters[flt - 1]) == NULL) {
3035: Log(LG_ERR, ("[%s] IFACE: Undefined filter: '%s'",
3036: b->name, av[0]));
3037: } else {
3038: struct bpf_program pr;
3039: char *buf;
3040: int bufbraces;
3041:
3042: #define ACL_BUF_SIZE 256*1024
3043: buf = Malloc(MB_IFACE, ACL_BUF_SIZE);
3044: buf[0] = 0;
3045: bufbraces = 0;
3046: while (f) {
3047: char *b1, *b2, *sbuf;
3048: sbuf = Mstrdup(MB_IFACE, f->rule);
3049: b2 = sbuf;
3050: b1 = strsep(&b2, " ");
3051: if (b2 != NULL) {
3052: if (strcasecmp(b1, "match") == 0) {
3053: strlcat(buf, "( ", ACL_BUF_SIZE);
3054: strlcat(buf, b2, ACL_BUF_SIZE);
3055: strlcat(buf, " ) ", ACL_BUF_SIZE);
3056: if (f->next) {
3057: strlcat(buf, "|| ( ", ACL_BUF_SIZE);
3058: bufbraces++;
3059: }
3060: } else if (strcasecmp(b1, "nomatch") == 0) {
3061: strlcat(buf, "( not ( ", ACL_BUF_SIZE);
3062: strlcat(buf, b2, ACL_BUF_SIZE);
3063: strlcat(buf, " ) ) ", ACL_BUF_SIZE);
3064: if (f->next) {
3065: strlcat(buf, "&& ( ", ACL_BUF_SIZE);
3066: bufbraces++;
3067: }
3068: } else {
3069: Log(LG_ERR, ("[%s] IFACE: filter action '%s' is unknown",
3070: b->name, b1));
3071: }
3072: };
3073: Freee(sbuf);
3074: f = f->next;
3075: }
3076: for (i = 0; i < bufbraces; i++)
3077: strlcat(buf, ") ", ACL_BUF_SIZE);
3078: Log(LG_IFACE2, ("[%s] IFACE: flt%d: '%s'",
3079: b->name, flt, buf));
3080:
3081: if (pcap_compile_nopcap((u_int)-1, DLT_RAW, &pr, buf, 1, 0xffffff00)) {
3082: Log(LG_ERR, ("[%s] IFACE: filter '%s' compilation error",
3083: b->name, av[0]));
3084: /* Incorrect matches nothing. */
3085: hp->bpf_prog_len = NOMATCH_PROG_LEN;
3086: memcpy(&hp->bpf_prog, &gNoMatchProg,
3087: NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
3088: } else if (pr.bf_len > ACL_MAX_PROGLEN) {
3089: Log(LG_ERR, ("[%s] IFACE: filter '%s' is too long",
3090: b->name, av[0]));
3091: pcap_freecode(&pr);
3092: /* Incorrect matches nothing. */
3093: hp->bpf_prog_len = NOMATCH_PROG_LEN;
3094: memcpy(&hp->bpf_prog, &gNoMatchProg,
3095: NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
3096: } else {
3097: hp->bpf_prog_len = pr.bf_len;
3098: memcpy(&hp->bpf_prog, pr.bf_insns,
3099: pr.bf_len * sizeof(struct bpf_insn));
3100: pcap_freecode(&pr);
3101: }
3102: Freee(buf);
3103: }
3104: } else {
3105: Log(LG_ERR, ("[%s] IFACE: incorrect filter: '%s'",
3106: b->name, av[0]));
3107: /* Incorrect matches nothing. */
3108: hp->bpf_prog_len = NOMATCH_PROG_LEN;
3109: memcpy(&hp->bpf_prog, &gNoMatchProg,
3110: NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
3111: }
3112:
3113: /* Prepare action */
3114: p = 1;
3115: if (ac == 1) {
3116: if (!l->next) {
3117: strcpy(hp->ifMatch, outhook);
3118: strcpy(inhookn[0], "");
3119: } else {
3120: sprintf(hp->ifMatch, "%d-%d-m", dir, num);
3121: sprintf(inhookn[0], "%d-%d-mi", dir, num);
3122:
3123: /* Connect nomatch hook to bpf itself. */
3124: strcpy(cn.ourhook, hp->ifMatch);
3125: strcpy(cn.path, path);
3126: strcpy(cn.peerhook, inhookn[0]);
3127: if (NgSendMsg(gLinksCsock, path,
3128: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
3129: Perror("[%s] IFACE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
3130: b->name, path, cn.ourhook, cn.path, cn.peerhook);
3131: }
3132: strcpy(stathook, inhookn[0]);
3133: }
3134: } else if (strcasecmp(av[p], "pass") == 0) {
3135: strcpy(hp->ifMatch, outhook);
3136: strcpy(inhookn[0], "");
3137: } else if (strcasecmp(av[p], "deny") == 0) {
3138: strcpy(hp->ifMatch, "deny");
3139: strcpy(inhookn[0], "");
3140: #ifdef USE_NG_CAR
3141: } else if ((strcasecmp(av[p], "shape") == 0) ||
3142: (strcasecmp(av[p], "rate-limit") == 0)) {
3143: struct ngm_mkpeer mp;
3144: struct ng_car_bulkconf car;
3145: char tmppath[NG_PATHSIZ];
3146:
3147: sprintf(hp->ifMatch, "%d-%d-m", dir, num);
3148:
3149: /* Create a car node for traffic shaping. */
3150: strcpy(mp.type, NG_CAR_NODE_TYPE);
3151: snprintf(mp.ourhook, sizeof(mp.ourhook), "%d-%d-m", dir, num);
3152: strcpy(mp.peerhook, ((dir == 0)?NG_CAR_HOOK_LOWER:NG_CAR_HOOK_UPPER));
3153: if (NgSendMsg(gLinksCsock, path,
3154: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
3155: Perror("[%s] IFACE: can't create %s node at \"%s\"->\"%s\"",
3156: b->name, NG_CAR_NODE_TYPE, path, mp.ourhook);
3157: }
3158:
3159: snprintf(tmppath, sizeof(tmppath), "%s%d-%d-m", path, dir, num);
3160:
3161: /* Connect car to bpf. */
3162: snprintf(cn.ourhook, sizeof(cn.ourhook), "%d-%d-mi", dir, num);
3163: strlcpy(cn.path, tmppath, sizeof(cn.path));
3164: strcpy(cn.peerhook, ((dir == 0)?NG_CAR_HOOK_UPPER:NG_CAR_HOOK_LOWER));
3165: if (NgSendMsg(gLinksCsock, path,
3166: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
3167: Perror("[%s] IFACE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
3168: b->name, path, cn.ourhook, cn.path, cn.peerhook);
3169: }
3170:
3171: bzero(&car, sizeof(car));
3172:
3173: if (strcasecmp(av[p], "shape") == 0) {
3174: car.upstream.mode = NG_CAR_SHAPE;
3175: } else {
3176: car.upstream.mode = NG_CAR_RED;
3177: }
3178: p++;
3179:
3180: if ((ac > p) && (av[p][0] >= '0') && (av[p][0] <= '9')) {
3181: car.upstream.cir = atol(av[p]);
3182: p++;
3183: if ((ac > p) && (av[p][0] >= '0') && (av[p][0] <= '9')) {
3184: car.upstream.cbs = atol(av[p]);
3185: p++;
3186: if ((ac > p) && (av[p][0] >= '0') && (av[p][0] <= '9')) {
3187: car.upstream.ebs = atol(av[p]);
3188: p++;
3189: } else {
3190: car.upstream.ebs = car.upstream.cbs * 2;
3191: }
3192: } else {
3193: car.upstream.cbs = car.upstream.cir / 8;
3194: car.upstream.ebs = car.upstream.cbs * 2;
3195: }
3196: } else {
3197: car.upstream.cir = 8000;
3198: car.upstream.cbs = car.upstream.cir / 8;
3199: car.upstream.ebs = car.upstream.cbs * 2;
3200: }
3201: car.upstream.green_action = NG_CAR_ACTION_FORWARD;
3202: car.upstream.yellow_action = NG_CAR_ACTION_FORWARD;
3203: car.upstream.red_action = NG_CAR_ACTION_DROP;
3204:
3205: car.downstream = car.upstream;
3206:
3207: if (NgSendMsg(gLinksCsock, tmppath,
3208: NGM_CAR_COOKIE, NGM_CAR_SET_CONF, &car, sizeof(car)) < 0) {
3209: Perror("[%s] IFACE: can't set %s configuration",
3210: b->name, NG_CAR_NODE_TYPE);
3211: }
3212:
3213: if (ac > p) {
3214: if (strcasecmp(av[p], "pass") == 0) {
3215: union {
3216: u_char buf[NG_BPF_HOOKPROG_SIZE(MATCH_PROG_LEN)];
3217: struct ng_bpf_hookprog hprog;
3218: } hpu1;
3219: struct ng_bpf_hookprog *const hp1 = &hpu1.hprog;
3220:
3221: memset(&hpu1, 0, sizeof(hpu1));
3222: strcpy(hp1->ifMatch, outhook);
3223: strcpy(hp1->ifNotMatch, outhook);
3224: hp1->bpf_prog_len = MATCH_PROG_LEN;
3225: memcpy(&hp1->bpf_prog, &gMatchProg,
3226: MATCH_PROG_LEN * sizeof(*gMatchProg));
3227: sprintf(hp1->thisHook, "%d-%d-mi", dir, num);
3228: if (NgSendMsg(gLinksCsock, path, NGM_BPF_COOKIE, NGM_BPF_SET_PROGRAM,
3229: hp1, NG_BPF_HOOKPROG_SIZE(hp1->bpf_prog_len)) < 0) {
3230: Perror("[%s] IFACE: can't set %s node program",
3231: b->name, NG_BPF_NODE_TYPE);
3232: }
3233:
3234: strcpy(stathook, hp1->thisHook);
3235: strcpy(inhookn[0], "");
3236: } else {
3237: Log(LG_ERR, ("[%s] IFACE: unknown action: '%s'",
3238: b->name, av[p]));
3239: strcpy(inhookn[0], "");
3240: }
3241: } else {
3242: sprintf(inhookn[0], "%d-%d-mi", dir, num);
3243: strcpy(stathook, inhookn[0]);
3244: }
3245: #endif /* USE_NG_CAR */
3246: } else {
3247: Log(LG_ERR, ("[%s] IFACE: unknown action: '%s'",
3248: b->name, av[1]));
3249: strcpy(inhookn[0], "");
3250: }
3251:
3252: /* Prepare nomatch */
3253: if (l->next && strcasecmp(av[0], "all")) {
3254: /* If there is next limit and there is possible nomatch,
3255: * then pass nomatch there. */
3256: sprintf(hp->ifNotMatch, "%d-%d-n", dir, num);
3257: sprintf(inhookn[1], "%d-%d-ni", dir, num);
3258:
3259: /* Connect nomatch hook to bpf itself. */
3260: strcpy(cn.ourhook, hp->ifNotMatch);
3261: strcpy(cn.path, path);
3262: strcpy(cn.peerhook, inhookn[1]);
3263: if (NgSendMsg(gLinksCsock, path,
3264: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
3265: Perror("[%s] IFACE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
3266: b->name, path, cn.ourhook, cn.path, cn.peerhook);
3267: }
3268: } else {
3269: /* There is no next limit, pass nomatch. */
3270: strcpy(hp->ifNotMatch, outhook);
3271: strcpy(inhookn[1], "");
3272: }
3273:
3274: /* Remember how to collect stats for this limit */
3275: if (l->name[0]) {
3276: SLIST_FOREACH(ss, &b->iface.ss[dir], next) {
3277: if (strcmp(ss->name, l->name) == 0)
3278: break;
3279: }
3280: if (ss == NULL) {
3281: ss = Malloc(MB_IFACE, sizeof(*ss));
3282: strlcpy(ss->name, l->name, sizeof(ss->name));
3283: SLIST_INIT(&ss->src);
3284: SLIST_INSERT_HEAD(&b->iface.ss[dir], ss, next);
3285: }
3286: if (stathook[0]) {
3287: sss = Malloc(MB_IFACE, sizeof(*sss));
3288: strlcpy(sss->hook, stathook, sizeof(sss->hook));
3289: sss->type = SSSS_IN;
3290: SLIST_INSERT_HEAD(&ss->src, sss, next);
3291: }
3292: }
3293:
3294: for (i = 0; i < 2; i++) {
3295: if (inhook[i][0] != 0) {
3296: if (l->name[0] && !stathook[0]) {
3297: sss = Malloc(MB_IFACE, sizeof(*sss));
3298: strlcpy(sss->hook, inhook[i], sizeof(sss->hook));
3299: sss->type = SSSS_MATCH;
3300: SLIST_INSERT_HEAD(&ss->src, sss, next);
3301: }
3302:
3303: strcpy(hp->thisHook, inhook[i]);
3304: if (NgSendMsg(gLinksCsock, path, NGM_BPF_COOKIE, NGM_BPF_SET_PROGRAM,
3305: hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0) {
3306: Perror("[%s] IFACE: can't set %s node program",
3307: b->name, NG_BPF_NODE_TYPE);
3308: }
3309: }
3310: strcpy(inhook[i], inhookn[i]);
3311: }
3312:
3313: num++;
3314: }
3315:
3316: /* Connect left hooks to output */
3317: for (i = 0; i < 2; i++) {
3318: if (inhook[i][0] != 0) {
3319: memset(hpu, 0, sizeof(*hpu));
3320: strcpy(hp->thisHook, inhook[i]);
3321: hp->bpf_prog_len = MATCH_PROG_LEN;
3322: memcpy(&hp->bpf_prog, &gMatchProg,
3323: MATCH_PROG_LEN * sizeof(*gMatchProg));
3324: strcpy(hp->ifMatch, outhook);
3325: strcpy(hp->ifNotMatch, outhook);
3326: if (NgSendMsg(gLinksCsock, path, NGM_BPF_COOKIE, NGM_BPF_SET_PROGRAM,
3327: hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0) {
3328: Perror("[%s] IFACE: can't set %s node %s %s program (2)",
3329: b->name, NG_BPF_NODE_TYPE, path, hp->thisHook);
3330: }
3331: }
3332: }
3333: }
3334: }
3335: Freee(hpu);
3336: }
3337:
3338: static void
3339: IfaceShutdownLimits(Bund b)
3340: {
3341: char path[NG_PATHSIZ];
3342: struct svcs *ss;
3343: struct svcssrc *sss;
3344: struct svcstat curstats;
3345: int i;
3346:
3347: if (b->n_up > 0) {
3348: bzero(&curstats, sizeof(curstats));
3349: IfaceGetStats(b, &curstats);
3350: IfaceAddStats(&b->iface.prevstats, &curstats);
3351: IfaceFreeStats(&curstats);
3352: }
3353:
3354: if (b->params.acl_limits[0] || b->params.acl_limits[1]) {
3355: snprintf(path, sizeof(path), "[%x]:", b->iface.limitID);
3356: NgFuncShutdownNode(gLinksCsock, b->name, path);
3357: }
3358:
3359: for (i = 0; i < ACL_DIRS; i++) {
3360: while ((ss = SLIST_FIRST(&b->iface.ss[i])) != NULL) {
3361: while ((sss = SLIST_FIRST(&ss->src)) != NULL) {
3362: SLIST_REMOVE_HEAD(&ss->src, next);
3363: Freee(sss);
3364: }
3365: SLIST_REMOVE_HEAD(&b->iface.ss[i], next);
3366: Freee(ss);
3367: }
3368: }
3369: }
3370:
3371: void
3372: IfaceGetStats(Bund b, struct svcstat *stat)
3373: {
3374: char path[NG_PATHSIZ];
3375: struct svcs *ss;
3376: struct svcssrc *sss;
3377: int dir;
3378:
3379: union {
3380: u_char buf[sizeof(struct ng_mesg) + sizeof(struct ng_bpf_hookstat)];
3381: struct ng_mesg reply;
3382: } u;
3383: struct ng_bpf_hookstat *const hs = (struct ng_bpf_hookstat *)(void *)u.reply.data;
3384:
3385: snprintf(path, sizeof(path), "[%x]:", b->iface.limitID);
3386: for (dir = 0; dir < ACL_DIRS; dir++) {
3387: SLIST_FOREACH(ss, &b->iface.ss[dir], next) {
3388: struct svcstatrec *ssr;
3389:
3390: SLIST_FOREACH(ssr, &stat->stat[dir], next) {
3391: if (strcmp(ssr->name, ss->name) == 0)
3392: break;
3393: }
3394: if (!ssr) {
3395: ssr = Malloc(MB_IFACE, sizeof(*ssr));
3396: strlcpy(ssr->name, ss->name, sizeof(ssr->name));
3397: SLIST_INSERT_HEAD(&stat->stat[dir], ssr, next);
3398: }
3399:
3400: SLIST_FOREACH(sss, &ss->src, next) {
3401: if (NgSendMsg(gLinksCsock, path,
3402: NGM_BPF_COOKIE, NGM_BPF_GET_STATS, sss->hook, strlen(sss->hook)+1) < 0)
3403: continue;
3404: if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0)
3405: continue;
3406:
3407: switch(sss->type) {
3408: case SSSS_IN:
3409: ssr->Packets += hs->recvFrames;
3410: ssr->Octets += hs->recvOctets;
3411: break;
3412: case SSSS_MATCH:
3413: ssr->Packets += hs->recvMatchFrames;
3414: ssr->Octets += hs->recvMatchOctets;
3415: break;
3416: case SSSS_NOMATCH:
3417: ssr->Packets += hs->recvFrames - hs->recvMatchFrames;
3418: ssr->Octets += hs->recvOctets - hs->recvMatchOctets;
3419: break;
3420: case SSSS_OUT:
3421: ssr->Packets += hs->xmitFrames;
3422: ssr->Octets += hs->xmitOctets;
3423: break;
3424: }
3425: }
3426: }
3427: }
3428: }
3429:
3430: void
3431: IfaceAddStats(struct svcstat *stat1, struct svcstat *stat2)
3432: {
3433: struct svcstatrec *ssr1, *ssr2;
3434: int dir;
3435:
3436: for (dir = 0; dir < ACL_DIRS; dir++) {
3437: SLIST_FOREACH(ssr2, &stat2->stat[dir], next) {
3438: SLIST_FOREACH(ssr1, &stat1->stat[dir], next)
3439: if (strcmp(ssr1->name, ssr2->name) == 0) {
3440: break;
3441: }
3442: if (!ssr1) {
3443: ssr1 = Malloc(MB_IFACE, sizeof(*ssr1));
3444: strlcpy(ssr1->name, ssr2->name, sizeof(ssr1->name));
3445: SLIST_INSERT_HEAD(&stat1->stat[dir], ssr1, next);
3446: }
3447: ssr1->Packets += ssr2->Packets;
3448: ssr1->Octets += ssr2->Octets;
3449: }
3450: }
3451: }
3452:
3453: void
3454: IfaceFreeStats(struct svcstat *stat)
3455: {
3456: struct svcstatrec *ssr;
3457: int i;
3458:
3459: for (i = 0; i < ACL_DIRS; i++) {
3460: while ((ssr = SLIST_FIRST(&stat->stat[i])) != NULL) {
3461: SLIST_REMOVE_HEAD(&stat->stat[i], next);
3462: Freee(ssr);
3463: }
3464: }
3465: }
3466: #endif /* USE_NG_BPF */
3467:
3468: /*
3469: * IfaceSetName()
3470: */
3471:
3472: int
3473: IfaceSetName(Bund b, const char * ifname)
3474: {
3475: IfaceState const iface = &b->iface;
3476: struct ifreq ifr;
3477: int s;
3478:
3479: /* Do not rename interface on template */
3480: if (b->tmpl)
3481: return(0);
3482:
3483: /* Do not wait ioctl error "file already exist" */
3484: if (strncmp(iface->ifname, ifname, sizeof(iface->ifname)) == 0)
3485: return(0);
3486:
3487: /* Get socket */
3488: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
3489: Log(LG_ERR, ("[%s] IFACE: Can't get socket to set name", b->name));
3490: return(-1);
3491: }
3492:
3493: /* Set name of interface */
3494: memset(&ifr, 0, sizeof(ifr));
3495: strlcpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name));
3496: ifr.ifr_data = (caddr_t)ifname;
3497: Log(LG_IFACE2, ("[%s] IFACE: setting \"%s\" name to \"%s\"",
3498: b->name, iface->ifname, ifname));
3499:
3500: if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
3501: Perror("[%s] IFACE: ioctl(%s, SIOCSIFNAME)", b->name, iface->ifname);
3502: close(s);
3503: return(-1);
3504: }
3505:
3506: close(s);
3507: /* Save name */
3508: strlcpy(iface->ifname, ifname, sizeof(iface->ifname));
3509: return(0);
3510: }
3511:
3512: #ifdef SIOCSIFDESCR
3513: /*
3514: * IfaceSetDescr()
3515: */
3516:
3517: int
3518: IfaceSetDescr(Bund b, const char * ifdescr)
3519: {
3520: IfaceState const iface = &b->iface;
3521: struct ifreq ifr;
3522: int s, ifdescr_maxlen;
3523: char *newdescr;
3524: size_t sz = sizeof(int);
3525:
3526: if (b->tmpl) {
3527: Log(LG_ERR, ("Impossible ioctl(SIOCSIFDESCR) on template"));
3528: return(-1);
3529: }
3530:
3531: if (sysctlbyname("net.ifdescr_maxlen", &ifdescr_maxlen, &sz, NULL, 0) < 0) {
3532: Perror("[%s] IFACE: sysctl net.ifdescr_maxlen failed", b->name);
3533: return(-1);
3534: }
3535:
3536: if (ifdescr_maxlen < strlen(ifdescr) + 1) {
3537: Log(LG_ERR, ("[%s] IFACE: Description too long, >%d characters",
3538: b->name, ifdescr_maxlen-1));
3539: return(-1);
3540: }
3541:
3542: /* Get socket */
3543: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
3544: Log(LG_ERR, ("[%s] IFACE: Can't get socket to set description", b->name));
3545: return(-1);
3546: }
3547:
3548: /* Set description of interface */
3549: memset(&ifr, 0, sizeof(ifr));
3550: strlcpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name));
3551: ifr.ifr_buffer.length = strlen(ifdescr) + 1;
3552: if (ifr.ifr_buffer.length == 1) {
3553: ifr.ifr_buffer.buffer = newdescr = NULL;
3554: ifr.ifr_buffer.length = 0;
3555: Log(LG_IFACE2, ("[%s] IFACE: clearing \"%s\" description",
3556: b->name, iface->ifname));
3557: } else {
3558: newdescr = Mstrdup(MB_IFACE, ifdescr);
3559: ifr.ifr_buffer.buffer = newdescr;
3560: Log(LG_IFACE2, ("[%s] IFACE: setting \"%s\" description to \"%s\"",
3561: b->name, iface->ifname, ifdescr));
3562: }
3563:
3564: if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) {
3565: Perror("[%s] IFACE: ioctl(%s, SIOCSIFDESCR)", b->name, iface->ifname);
3566: Freee(newdescr);
3567: close(s);
3568: return(-1);
3569: }
3570: Freee(newdescr);
3571: close(s);
3572: return(0);
3573: }
3574: #endif /* SIOCSIFDESCR */
3575: #ifdef SIOCAIFGROUP
3576: /*
3577: * IfaceAddGroup()
3578: */
3579:
3580: int
3581: IfaceAddGroup(Bund b, const char * ifgroup)
3582: {
3583: IfaceState const iface = &b->iface;
3584: struct ifgroupreq ifgr;
3585: int s, i;
3586:
3587: /* Do not add group on template */
3588: if (b->tmpl)
3589: return(0);
3590:
3591: if (ifgroup[0] && isdigit(ifgroup[strlen(ifgroup) - 1])) {
3592: Perror("[%s] IFACE: groupnames may not end in a digit", b->name);
3593: return(-1);
3594: }
3595:
3596: /* Get socket */
3597: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
3598: Perror("[%s] IFACE: Can't get socket to add group", b->name);
3599: return(-1);
3600: }
3601:
3602: /* Add interface group */
3603: memset(&ifgr, 0, sizeof(ifgr));
3604: strlcpy(ifgr.ifgr_name, iface->ifname, sizeof(ifgr.ifgr_name));
3605: strlcpy(ifgr.ifgr_group, ifgroup, sizeof(ifgr.ifgr_group));
3606:
3607: Log(LG_IFACE2, ("[%s] IFACE: adding interface %s to group %s",
3608: b->name, iface->ifname, ifgroup));
3609:
3610: i = ioctl(s, SIOCAIFGROUP, (caddr_t)&ifgr);
3611: if (i < 0 && i != EEXIST) {
3612: Perror("[%s] IFACE: ioctl(%s, SIOCAIFGROUP)", b->name, iface->ifname);
3613: close(s);
3614: return(-1);
3615: }
3616:
3617: close(s);
3618: return(0);
3619: }
3620:
3621: /*
3622: * IfaceDelGroup()
3623: */
3624: int
3625: IfaceDelGroup(Bund b, const char * ifgroup)
3626: {
3627: IfaceState const iface = &b->iface;
3628: struct ifgroupreq ifgr;
3629: int s;
3630:
3631: /* Get socket */
3632: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
3633: Perror("[%s] IFACE: Can't get socket to delete from group", b->name);
3634: return(-1);
3635: }
3636:
3637: if (ifgroup[0] && isdigit(ifgroup[strlen(ifgroup) - 1])) {
3638: Perror("[%s] IFACE: groupnames may not end in a digit", b->name);
3639: return(-1);
3640: }
3641:
3642: /* Set interface group */
3643: memset(&ifgr, 0, sizeof(ifgr));
3644: strlcpy(ifgr.ifgr_name, iface->ifname, sizeof(ifgr.ifgr_name));
3645: strlcpy(ifgr.ifgr_group, ifgroup, sizeof(ifgr.ifgr_group));
3646:
3647: Log(LG_IFACE2, ("[%s] IFACE: remove interface %s from group %s",
3648: b->name, iface->ifname, ifgroup));
3649:
3650: if (ioctl(s, SIOCDIFGROUP, (caddr_t)&ifgr) == -1) {
3651: Perror("[%s] IFACE: ioctl(%s, SIOCDIFGROUP)", b->name, iface->ifname);
3652: close(s);
3653: return(-1);
3654: }
3655: close(s);
3656: return(0);
3657: }
3658: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>