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