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