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