--- embedaddon/mpd/src/iface.c 2012/02/21 23:32:47 1.1.1.1 +++ embedaddon/mpd/src/iface.c 2013/07/22 08:44:29 1.1.1.2 @@ -19,8 +19,10 @@ #include "netgraph.h" #include "util.h" +#include #include #include +#include #include #include #include @@ -59,6 +61,8 @@ #include #endif +#include + /* * DEFINITIONS */ @@ -94,7 +98,7 @@ static void IfaceNgIpv6Shutdown(Bund b); #ifdef USE_NG_NETFLOW - static int IfaceInitNetflow(Bund b, char *path, char *hook, char in, char out); + static int IfaceInitNetflow(Bund b, char *path, char *hook, char in, char out, int v6); static int IfaceSetupNetflow(Bund b, char in, char out); static void IfaceShutdownNetflow(Bund b, char in, char out); #endif @@ -142,6 +146,7 @@ static int IfaceSetName(Bund b, const char * ifname); #ifdef SIOCSIFDESCR static int IfaceSetDescr(Bund b, const char * ifdescr); + static void IfaceFreeDescr(IfaceState iface); #endif #ifdef SIOCAIFGROUP static int IfaceAddGroup(Bund b, const char * ifgroup); @@ -258,6 +263,17 @@ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}} static const struct in6_addr in6mask128 = IN6MASK128; +#ifdef SIOCSIFDESCR +void +IfaceFreeDescr(IfaceState iface) +{ + if (iface->ifdescr != NULL) + Freee(iface->ifdescr); + if (iface->conf.ifdescr != NULL) + Freee(iface->conf.ifdescr); + iface->ifdescr = iface->conf.ifdescr = NULL; +} +#endif /* * IfaceInit() @@ -298,6 +314,13 @@ IfaceInst(Bund b, Bund bt) memcpy(iface, &bt->iface, sizeof(*iface)); +#ifdef SIOCSIFDESCR + /* Copy interface description from template config to current */ + if (bt->iface.conf.ifdescr) + iface->conf.ifdescr = Mstrdup(MB_IFACE, bt->iface.conf.ifdescr); + if (bt->iface.ifdescr) + iface->ifdescr = Mstrdup(MB_IFACE, bt->iface.ifdescr); +#endif /* Copy interface name from template config to current */ if (bt->iface.conf.ifname[0] != 0 && b->tmpl == 0) { snprintf(iface->conf.ifname, sizeof(iface->conf.ifname), "%s%d", @@ -316,8 +339,7 @@ IfaceDestroy(Bund b) #ifdef SIOCSIFDESCR IfaceState const iface = &b->iface; - if (iface->conf.ifdescr != NULL) - Freee(iface->conf.ifdescr); + IfaceFreeDescr(iface); #endif } @@ -488,9 +510,13 @@ IfaceUp(Bund b, int ready) if (b->params.ifdescr != NULL) { if (IfaceSetDescr(b, b->params.ifdescr) != -1) { Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add description \"%s\"", - b->name, b->params.ifdescr)); - iface->ifdescr = b->params.ifdescr; + b->name, iface->ifdescr)); } + } else if (iface->conf.ifdescr != NULL) { + if (IfaceSetDescr(b, iface->conf.ifdescr) != -1) { + Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add description \"%s\"", + b->name, iface->ifdescr)); + } } #endif #ifdef SIOCAIFGROUP @@ -565,7 +591,7 @@ IfaceUp(Bund b, int ready) } acls = b->params.acl_table; while (acls != NULL) { - acl = Mdup(MB_IFACE, acls, sizeof(struct acl) + strlen(acls->rule)); + acl = Mdup(MB_IPFW, acls, sizeof(struct acl) + strlen(acls->rule)); acl->next = iface->tables; iface->tables = acl; ExecCmd(LG_IFACE2, b->name, "%s table %d add %s", PATH_IPFW, acls->real_number, acls->rule); @@ -688,6 +714,12 @@ IfaceDown(Bund b) PATH_IPFW, cb); #endif /* USE_IPFW */ + /* Clearing self and peer addresses */ + u_rangeclear(&iface->self_addr); + u_addrclear(&iface->peer_addr); + u_addrclear(&iface->self_ipv6_addr); + u_addrclear(&iface->peer_ipv6_addr); + /* Revert interface name and description */ if (strcmp(iface->ngname, iface->ifname) != 0) { @@ -704,22 +736,14 @@ IfaceDown(Bund b) } } #ifdef SIOCSIFDESCR - if (iface->ifdescr != NULL) { + if ((iface->ifdescr != NULL) + && (IfaceSetDescr(b, iface->conf.ifdescr) != -1)) { if (iface->conf.ifdescr != NULL) { - /* Restore to config defined */ - if (IfaceSetDescr(b, iface->conf.ifdescr) != -1) { Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Set description \"%s\"", - b->name, iface->conf.ifdescr)); - iface->ifdescr = iface->conf.ifdescr; - } else - iface->ifdescr = NULL; + b->name, iface->ifdescr)); } else { - /* Restore to original (empty) */ - if (IfaceSetDescr(b, "") != -1) { Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Clear description", b->name)); - } - iface->ifdescr = NULL; } } #endif @@ -770,7 +794,7 @@ IfaceAllocACL(struct acl_pool ***ap, int start, char * int i; struct acl_pool **rp,*rp1; - rp1 = Malloc(MB_IFACE, sizeof(struct acl_pool)); + rp1 = Malloc(MB_IPFW, sizeof(struct acl_pool)); strlcpy(rp1->ifname, ifname, sizeof(rp1->ifname)); rp1->acl_number = number; @@ -831,8 +855,8 @@ IFaceParseACL (char * src, char * ifname) int num,real_number; struct acl_pool *ap; - buf = Malloc(MB_IFACE, ACL_LEN); - buf1 = Malloc(MB_IFACE, ACL_LEN); + buf = Malloc(MB_IPFW, ACL_LEN); + buf1 = Malloc(MB_IPFW, ACL_LEN); strlcpy(buf, src, ACL_LEN); do { @@ -1512,23 +1536,14 @@ IfaceSetCommand(Context ctx, int ac, char *av[], void break; #ifdef SIOCSIFDESCR case SET_DESCR: - if (ctx->bund->tmpl) - Error("Impossible to apply on template"); - if (iface->conf.ifdescr != NULL) - Freee(iface->conf.ifdescr); - iface->conf.ifdescr = NULL; - iface->ifdescr = NULL; + IfaceFreeDescr(iface); switch (ac) { case 0: return IfaceSetDescr(ctx->bund, ""); break; case 1: iface->conf.ifdescr = Mstrdup(MB_IFACE, av[0]); - if (IfaceSetDescr(ctx->bund, av[0]) == 0) { - iface->ifdescr = iface->conf.ifdescr; - return(0); - } else - return(-1); + return IfaceSetDescr(ctx->bund, av[0]); break; default: return(-1); @@ -1612,7 +1627,7 @@ IfaceStat(Context ctx, int ac, char *av[], void *arg) Printf("\tName : %s\r\n", iface->conf.ifname); #ifdef SIOCSIFDESCR Printf("\tDescription : \"%s\"\r\n", - (iface->conf.ifdescr != NULL) ? iface->conf.ifdescr : ""); + (iface->ifdescr != NULL) ? iface->ifdescr : ""); #endif #ifdef SIOCAIFGROUP Printf("\tGroup : %s\r\n", iface->conf.ifgroup); @@ -1785,8 +1800,8 @@ IfaceChangeFlags(Bund b, int clear, int set) struct ifreq ifrq; int s, new_flags; - Log(LG_IFACE2, ("[%s] IFACE: Change interface flags: -%d +%d", - b->name, clear, set)); + Log(LG_IFACE2, ("[%s] IFACE: Change interface %s flags: -%d +%d", + b->name, b->iface.ifname, clear, set)); if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { Perror("[%s] IFACE: Can't get socket to change interface flags", b->name); @@ -1795,9 +1810,8 @@ IfaceChangeFlags(Bund b, int clear, int set) memset(&ifrq, '\0', sizeof(ifrq)); strlcpy(ifrq.ifr_name, b->iface.ifname, sizeof(ifrq.ifr_name)); - ifrq.ifr_name[sizeof(ifrq.ifr_name) - 1] = '\0'; if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { - Perror("[%s] IFACE: ioctl(%s, %s)", b->name, b->iface.ifname, "SIOCGIFFLAGS"); + Perror("[%s] IFACE: ioctl(SIOCGIFFLAGS, %s)", b->name, b->iface.ifname); close(s); return; } @@ -1810,7 +1824,7 @@ IfaceChangeFlags(Bund b, int clear, int set) ifrq.ifr_flagshigh = new_flags >> 16; if (ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { - Perror("[%s] IFACE: ioctl(%s, %s)", b->name, b->iface.ifname, "SIOCSIFFLAGS"); + Perror("[%s] IFACE: ioctl(SIOCSIFFLAGS, %s)", b->name, b->iface.ifname); close(s); return; } @@ -1902,8 +1916,14 @@ IfaceChangeAddr(Bund b, int add, struct u_range *self, res = ioctl(s, add?SIOCAIFADDR_IN6:SIOCDIFADDR_IN6, &ifra6); if (res == -1) { - Perror("[%s] IFACE: %s IPv6 address %s %s failed", - b->name, add?"Adding":"Removing", add?"to":"from", b->iface.ifname); + if (add && errno == EEXIST) { + /* this can happen if the kernel has already automatically added + the same link-local address - ignore the error */ + res = 0; + } else { + Perror("[%s] IFACE: %s IPv6 address %s %s failed", + b->name, add?"Adding":"Removing", add?"to":"from", b->iface.ifname); + } } break; @@ -2106,7 +2126,7 @@ IfaceNgIpInit(Bund b, int ready) Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) { if (IfaceInitNetflow(b, path, hook, Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)?1:0, - Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)?1:0)) + Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)?1:0, 0)) goto fail; if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)) b->iface.nfin_up = 1; @@ -2116,13 +2136,13 @@ IfaceNgIpInit(Bund b, int ready) #else /* NG_NETFLOW_CONF_INGRESS */ /* Connect a netflow node if configured */ if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)) { - if (IfaceInitNetflow(b, path, hook, 1, 0)) + if (IfaceInitNetflow(b, path, hook, 1, 0, 0)) goto fail; b->iface.nfin_up = 1; } if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) { - if (IfaceInitNetflow(b, path, hook, 0, 1)) + if (IfaceInitNetflow(b, path, hook, 0, 1, 0)) goto fail; b->iface.nfout_up = 1; } @@ -2263,6 +2283,35 @@ IfaceNgIpv6Init(Bund b, int ready) b->iface.tee6_up = 1; } +#ifdef USE_NG_NETFLOW +#ifdef NG_NETFLOW_CONF_INGRESS + /* Connect a netflow node if configured */ + if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN) || + Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) { + if (IfaceInitNetflow(b, path, hook, + Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)?1:0, + Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)?1:0, 1)) + goto fail; + if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)) + b->iface.nfin_up = 1; + if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) + b->iface.nfout_up = 1; + } +#else /* NG_NETFLOW_CONF_INGRESS */ + /* Connect a netflow node if configured */ + if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN, 1)) { + if (IfaceInitNetflow(b, path, hook, 1, 0)) + goto fail; + b->iface.nfin_up = 1; + } + + if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) { + if (IfaceInitNetflow(b, path, hook, 0, 1, 1)) + goto fail; + b->iface.nfout_up = 1; + } +#endif /* NG_NETFLOW_CONF_INGRESS */ +#endif /* USE_NG_NETFLOW */ } /* Connect graph to the iface node. */ @@ -2276,6 +2325,21 @@ IfaceNgIpv6Init(Bund b, int ready) goto fail; } + if (ready) { +#ifdef USE_NG_NETFLOW +#ifdef NG_NETFLOW_CONF_INGRESS + if (b->iface.nfin_up || b->iface.nfout_up) + IfaceSetupNetflow(b, b->iface.nfin_up, b->iface.nfout_up); +#else /* NG_NETFLOW_CONF_INGRESS */ + if (b->iface.nfin_up) + IfaceSetupNetflow(b, 1, 0); + + if (b->iface.nfout_up) + IfaceSetupNetflow(b, 0, 1); +#endif /* NG_NETFLOW_CONF_INGRESS */ +#endif /* USE_NG_NETFLOW */ + } + /* OK */ return(0); @@ -2295,6 +2359,21 @@ IfaceNgIpv6Shutdown(Bund b) if (b->iface.tee6_up) IfaceShutdownTee(b, 1); b->iface.tee6_up = 0; +#ifdef USE_NG_NETFLOW +#ifdef NG_NETFLOW_CONF_INGRESS + if (b->iface.nfin_up || b->iface.nfout_up) + IfaceShutdownNetflow(b, b->iface.nfin_up, b->iface.nfout_up); + b->iface.nfin_up = 0; + b->iface.nfout_up = 0; +#else /* NG_NETFLOW_CONF_INGRESS */ + if (b->iface.nfin_up) + IfaceShutdownNetflow(b, 1, 0); + b->iface.nfin_up = 0; + if (b->iface.nfout_up) + IfaceShutdownNetflow(b, 0, 1); + b->iface.nfout_up = 0; +#endif /* NG_NETFLOW_CONF_INGRESS */ +#endif snprintf(path, sizeof(path), "[%x]:", b->nodeID); NgFuncDisconnect(gLinksCsock, b->name, path, NG_PPP_HOOK_IPV6); @@ -2381,7 +2460,14 @@ IfaceSetupNAT(Bund b) { NatState const nat = &b->iface.nat; char path[NG_PATHSIZ]; +#ifdef NG_NAT_DESC_LENGTH int k; + union { + u_char buf[sizeof(struct ng_mesg) + sizeof(uint32_t)]; + struct ng_mesg reply; + } u; + uint32_t *const nat_id = (uint32_t *)(void *)u.reply.data; +#endif if (u_addrempty(&nat->alias_addr)) { snprintf(path, sizeof(path), "mpd%d-%s-nat:", gPid, b->name); @@ -2396,31 +2482,46 @@ IfaceSetupNAT(Bund b) #ifdef NG_NAT_DESC_LENGTH /* redirect-port */ for(k = 0; k < NM_PORT; k++) { - if(nat->nrpt_id[k]) { + if(nat->nrpt_id[k] == -1) { if (NgSendMsg(gLinksCsock, path, NGM_NAT_COOKIE, NGM_NAT_REDIRECT_PORT, &nat->nrpt[k], sizeof(struct ng_nat_redirect_port)) < 0) { Perror("[%s] can't set NAT redirect-port", b->name); + } else { + if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0) { + Perror("[%s] can't recv NAT redirect-port message", b->name); + } else + nat->nrpt_id[k] = *nat_id; } } } /* redirect-addr */ for(k = 0; k < NM_ADDR; k++) { - if(nat->nrad_id[k]) { + if(nat->nrad_id[k] == -1) { if (NgSendMsg(gLinksCsock, path, NGM_NAT_COOKIE, NGM_NAT_REDIRECT_ADDR, &nat->nrad[k], sizeof(struct ng_nat_redirect_addr)) < 0) { Perror("[%s] can't set NAT redirect-addr", b->name); + } else { + if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0) { + Perror("[%s] can't recv NAT redirect-addr message", b->name); + } else + nat->nrad_id[k] = *nat_id; } } } /* redirect-proto */ for(k = 0; k < NM_PROTO; k++) { - if(nat->nrpr_id[k]) { + if(nat->nrpr_id[k] == -1) { if (NgSendMsg(gLinksCsock, path, NGM_NAT_COOKIE, NGM_NAT_REDIRECT_PROTO, &nat->nrpr[k], sizeof(struct ng_nat_redirect_proto)) < 0) { Perror("[%s] can't set NAT redirect-proto", b->name); + } else { + if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0) { + Perror("[%s] can't recv NAT redirect-proto message", b->name); + } else + nat->nrpr_id[k] = *nat_id; } } } @@ -2432,9 +2533,27 @@ static void IfaceShutdownNAT(Bund b) { char path[NG_PATHSIZ]; +#ifdef NG_NAT_DESC_LENGTH + NatState const nat = &b->iface.nat; + int k; +#endif snprintf(path, sizeof(path), "mpd%d-%s-nat:", gPid, b->name); NgFuncShutdownNode(gLinksCsock, b->name, path); +#ifdef NG_NAT_DESC_LENGTH + /* redirect-port */ + for(k = 0; k < NM_PORT; k++) + if(nat->nrpt_id[k] > 0) + nat->nrpt_id[k] = -1; + /* redirect-addr */ + for(k = 0; k < NM_ADDR; k++) + if(nat->nrad_id[k] > 0) + nat->nrad_id[k] = -1; + /* redirect-proto */ + for(k = 0; k < NM_PROTO; k++) + if(nat->nrpr_id[k] > 0) + nat->nrpr_id[k] = -1; +#endif } #endif /* USE_NG_NAT */ @@ -2580,7 +2699,7 @@ IfaceShutdownIpacct(Bund b) #ifdef USE_NG_NETFLOW static int -IfaceInitNetflow(Bund b, char *path, char *hook, char in, char out) +IfaceInitNetflow(Bund b, char *path, char *hook, char in, char out, int v6) { struct ngm_connect cn; int nif; @@ -2591,7 +2710,8 @@ IfaceInitNetflow(Bund b, char *path, char *hook, char nif = gNetflowIface + b->id*2 + out; #endif - Log(LG_IFACE2, ("[%s] IFACE: Connecting netflow (%s)", b->name, out?"out":"in")); + Log(LG_IFACE2, ("[%s] IFACE: Connecting netflow%s (%s)", + b->name, v6?"6":"", out?"out":"in")); /* Create global ng_netflow(4) node if not yet. */ if (gNetflowNodeID == 0) { @@ -2970,7 +3090,7 @@ IfaceSetupLimits(Bund b) struct ngm_connect cn; int i; - hpu = Malloc(MB_IFACE, sizeof(*hpu)); + hpu = Malloc(MB_ACL, sizeof(*hpu)); hp = &hpu->hprog; if (b->params.acl_limits[0] || b->params.acl_limits[1]) { @@ -3016,7 +3136,7 @@ IfaceSetupLimits(Bund b) } stathook[0] = 0; - memset(hpu, 0, sizeof(hpu)); + memset(hpu, 0, sizeof(*hpu)); /* Prepare filter */ if (strcasecmp(av[0], "all") == 0) { hp->bpf_prog_len = MATCH_PROG_LEN; @@ -3040,12 +3160,12 @@ IfaceSetupLimits(Bund b) int bufbraces; #define ACL_BUF_SIZE 256*1024 - buf = Malloc(MB_IFACE, ACL_BUF_SIZE); + buf = Malloc(MB_ACL, ACL_BUF_SIZE); buf[0] = 0; bufbraces = 0; while (f) { char *b1, *b2, *sbuf; - sbuf = Mstrdup(MB_IFACE, f->rule); + sbuf = Mstrdup(MB_ACL, f->rule); b2 = sbuf; b1 = strsep(&b2, " "); if (b2 != NULL) { @@ -3278,13 +3398,13 @@ IfaceSetupLimits(Bund b) break; } if (ss == NULL) { - ss = Malloc(MB_IFACE, sizeof(*ss)); + ss = Malloc(MB_ACL, sizeof(*ss)); strlcpy(ss->name, l->name, sizeof(ss->name)); SLIST_INIT(&ss->src); SLIST_INSERT_HEAD(&b->iface.ss[dir], ss, next); } if (stathook[0]) { - sss = Malloc(MB_IFACE, sizeof(*sss)); + sss = Malloc(MB_ACL, sizeof(*sss)); strlcpy(sss->hook, stathook, sizeof(sss->hook)); sss->type = SSSS_IN; SLIST_INSERT_HEAD(&ss->src, sss, next); @@ -3294,7 +3414,7 @@ IfaceSetupLimits(Bund b) for (i = 0; i < 2; i++) { if (inhook[i][0] != 0) { if (l->name[0] && !stathook[0]) { - sss = Malloc(MB_IFACE, sizeof(*sss)); + sss = Malloc(MB_ACL, sizeof(*sss)); strlcpy(sss->hook, inhook[i], sizeof(sss->hook)); sss->type = SSSS_MATCH; SLIST_INSERT_HEAD(&ss->src, sss, next); @@ -3392,7 +3512,7 @@ IfaceGetStats(Bund b, struct svcstat *stat) break; } if (!ssr) { - ssr = Malloc(MB_IFACE, sizeof(*ssr)); + ssr = Malloc(MB_ACL, sizeof(*ssr)); strlcpy(ssr->name, ss->name, sizeof(ssr->name)); SLIST_INSERT_HEAD(&stat->stat[dir], ssr, next); } @@ -3440,7 +3560,7 @@ IfaceAddStats(struct svcstat *stat1, struct svcstat *s break; } if (!ssr1) { - ssr1 = Malloc(MB_IFACE, sizeof(*ssr1)); + ssr1 = Malloc(MB_ACL, sizeof(*ssr1)); strlcpy(ssr1->name, ssr2->name, sizeof(ssr1->name)); SLIST_INSERT_HEAD(&stat1->stat[dir], ssr1, next); } @@ -3486,7 +3606,7 @@ IfaceSetName(Bund b, const char * ifname) /* Get socket */ if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { - Log(LG_ERR, ("[%s] IFACE: Can't get socket to set name", b->name)); + Perror("[%s] IFACE: Can't get socket to set name", b->name); return(-1); } @@ -3512,62 +3632,228 @@ IfaceSetName(Bund b, const char * ifname) #ifdef SIOCSIFDESCR /* * IfaceSetDescr() + * + * Set/clear our own interface description accessible in console/web interface + * and kernel level interface description if it is available. + * + * Template may contain conversion specifications: + * + * %% expands to single % sign; + * %a for interface local address; + * %A for peer address; + * %i for system interface index; + * %I for interface name; + * %l for name of bundle's first link + * %M for peer MAC address of bundle's first link + * %S for interface status (DoD/UP/DOWN) + * %t for type of bundle's first link (pppoe, pptp, l2tp etc.) + * %u for self auth name (or dash if self auth name not used) + * %U for peer auth name (or dash if peer has not authenticated) */ - int -IfaceSetDescr(Bund b, const char * ifdescr) +IfaceSetDescr(Bund b, const char * template) { IfaceState const iface = &b->iface; struct ifreq ifr; - int s, ifdescr_maxlen; + int s; + unsigned int ifdescr_maxlen = 1024; /* used as limit for old kernels */ char *newdescr; - size_t sz = sizeof(int); + size_t sz = sizeof(ifdescr_maxlen); + char *limit, *ifname; + const char *src; + int proceed; + char buf[64]; - if (b->tmpl) { - Log(LG_ERR, ("Impossible ioctl(SIOCSIFDESCR) on template")); - return(-1); + static int mib[2] = { -1, 0 }; /* MIB for net.ifdescr_maxlen */ + size_t miblen = sizeof(mib) / sizeof(mib[0]); + + /* + * Check whether running kernel supports interface description. + * Perform the check only once. + */ + if (mib[0] < 0 && sysctlnametomib("net.ifdescr_maxlen", mib, &miblen) < 0) { + mib[0] = 0; + Perror("[%s] IFACE: sysctl net.ifdescr_maxlen failed", b->name); } - if (sysctlbyname("net.ifdescr_maxlen", &ifdescr_maxlen, &sz, NULL, 0) < 0) { - Perror("[%s] IFACE: sysctl net.ifdescr_maxlen failed", b->name); - return(-1); + /* + * Fetch net.ifdescr_maxlen value every time to catch up with changes + */ + if (mib[0] && sysctl(mib, 2, &ifdescr_maxlen, &sz, NULL, 0) < 0) { + /* unexpected error from the kernel, use default value */ + Perror("[%s] IFACE: sysctl net.ifdescr_maxlen failed", b->name); + ifdescr_maxlen = 1024; } - if (ifdescr_maxlen < strlen(ifdescr) + 1) { - Log(LG_ERR, ("[%s] IFACE: Description too long, >%d characters", - b->name, ifdescr_maxlen-1)); - return(-1); + newdescr = NULL; + ifname = iface->ifname; + if (iface->ifdescr != NULL) { + Freee(iface->ifdescr); + iface->ifdescr = NULL; } + if ((src = template) != NULL) { + /* Will use Mstrdup() later for iface->ifdescr to free extra memory */ + if ((iface->ifdescr = newdescr = Malloc(MB_IFACE, ifdescr_maxlen)) == NULL) { + Log(LG_IFACE2, ("[%s] IFACE: no memory for interface %s description", + b->name, ifname ? ifname : "")); + return(-1); + } + + /* ifdescr_maxlen includes terminating zero */ + limit = newdescr + ifdescr_maxlen - 1; + + /* + * Perform template expansion + */ + proceed = 1; + while (proceed && *src && newdescr < limit) { + if (*src != '%') { /* ordinary symbol, just copy it and proceed */ + *newdescr++ = *src++; + continue; + } + if (!*(src+1)) { /* '%' at the end of template, just copy */ + *newdescr++ = *src++; + continue; + } + switch(*++src) { /* expand */ + case '%': /* %% got replaced with single % */ + *newdescr++ = *src; + break; + +#define DST_COPY(a) \ + do { const char *temp = a; \ + if (temp && *temp) { \ + if ((newdescr + strlen (temp)) <= limit) {\ + newdescr = stpcpy (newdescr, temp); \ + } else { \ + proceed = 0; \ + } \ + } else { \ + *newdescr++ = '-'; \ + } \ + } while(0) + + /* self address */ + case 'a': + { + char *sep; + u_rangetoa(&iface->self_addr, buf, sizeof(buf)); + /* cut netmask */ + if ((sep = strchr(buf, '/'))) + *sep = '\0'; + DST_COPY(buf); + } + break; + /* peer address */ + case 'A': + { + u_addrtoa (&iface->peer_addr, buf, sizeof(buf)); + DST_COPY(buf); + } + break; + /* interface index */ + case 'i': + { + snprintf (buf, sizeof(buf), "%u", iface->ifindex); + DST_COPY(buf); + } + break; + /* interface name */ + case 'I': + DST_COPY(iface->ifname); + break; + /* first link name */ + case 'l': + DST_COPY(b->links[0] ? b->links[0]->name : NULL); + break; + case 'M': + if(b->links[0]) { + PhysType const pt = b->links[0]->type; + if (pt && pt->peermacaddr) { + (*pt->peermacaddr)(b->links[0], buf, sizeof(buf)); + DST_COPY(buf); + } else { + DST_COPY("-"); + } + } else { + DST_COPY("-"); + } + break; + /* interface status */ + case 'S': + DST_COPY(iface->up ? (iface->dod ? "DoD" : "UP") : "DOWN"); + break; + /* first link type */ + case 't': + DST_COPY(b->links[0] ? b->links[0]->type->name : NULL); + break; + /* self auth name */ + case 'u': + DST_COPY(b->links[0] ? b->links[0]->lcp.auth.conf.authname : NULL); + break; + /* peer auth name */ + case 'U': + DST_COPY(b->params.authname); + break; +#undef DST_COPY + default: /* unrecognized specification, just copy */ + *newdescr++ = '%'; + if (newdescr < limit) + *newdescr++ = *src; + } /* switch(*++src) */ + ++src; + } /* while */ + *newdescr = '\0'; + + /* includes terminating zero */ + sz = newdescr - iface->ifdescr + 1; + if ((newdescr = Mstrdup(MB_IFACE, iface->ifdescr)) == NULL) { + Log(LG_IFACE2, ("[%s] IFACE: no memory for interface %s description", + b->name, ifname ? ifname : "")); + Freee(iface->ifdescr); + iface->ifdescr = NULL; + return(-1); + } + Freee(iface->ifdescr); + iface->ifdescr = newdescr; + } /* template != NULL */ + + /* Set description of interface */ + if (mib[0] == 0) + return(0); /* do not bother kernel if it is too old */ + + if (ifname == NULL || *ifname == '\0') + return(0); /* we have not set system interface name yet */ + /* Get socket */ if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { - Log(LG_ERR, ("[%s] IFACE: Can't get socket to set description", b->name)); + Perror("[%s] IFACE: Can't get socket to set description for %s", + b->name, ifname); return(-1); } - /* Set description of interface */ memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name)); - ifr.ifr_buffer.length = strlen(ifdescr) + 1; - if (ifr.ifr_buffer.length == 1) { - ifr.ifr_buffer.buffer = newdescr = NULL; + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (!newdescr || !*newdescr) { /* empty description or clearing request */ + ifr.ifr_buffer.buffer = NULL; ifr.ifr_buffer.length = 0; Log(LG_IFACE2, ("[%s] IFACE: clearing \"%s\" description", - b->name, iface->ifname)); + b->name, ifname)); } else { - newdescr = Mstrdup(MB_IFACE, ifdescr); + ifr.ifr_buffer.length = (unsigned)sz; ifr.ifr_buffer.buffer = newdescr; Log(LG_IFACE2, ("[%s] IFACE: setting \"%s\" description to \"%s\"", - b->name, iface->ifname, ifdescr)); + b->name, ifname, newdescr)); } if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) { - Perror("[%s] IFACE: ioctl(%s, SIOCSIFDESCR)", b->name, iface->ifname); - Freee(newdescr); + Perror("[%s] IFACE: ioctl(%s, SIOCSIFDESCR, \"%s\")", + b->name, ifname, newdescr ? newdescr : "" ); close(s); return(-1); } - Freee(newdescr); close(s); return(0); }