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