From 9aec88f29cf8145f887f31a4bfc7299f723b72e8 Mon Sep 17 00:00:00 2001 From: rsc Date: Sat, 31 Dec 2005 19:33:03 +0000 Subject: new --- src/libip/Darwin.c | 1 + src/libip/FreeBSD.c | 144 +++++++++++++++++++++++++++ src/libip/Linux.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++++ src/libip/NetBSD.c | 1 + src/libip/OpenBSD.c | 1 + src/libip/SunOS.c | 1 + src/libip/freeipifc.c | 20 ++++ src/libip/mkfile | 4 +- src/libip/myetheraddr.c | 51 ++++------ src/libip/myipaddr.c | 30 +++++- src/libip/none.c | 24 +++++ src/libip/readipifc.c | 194 ------------------------------------ 12 files changed, 493 insertions(+), 232 deletions(-) create mode 100644 src/libip/Darwin.c create mode 100644 src/libip/FreeBSD.c create mode 100644 src/libip/Linux.c create mode 100644 src/libip/NetBSD.c create mode 100644 src/libip/OpenBSD.c create mode 100644 src/libip/SunOS.c create mode 100644 src/libip/freeipifc.c create mode 100644 src/libip/none.c delete mode 100644 src/libip/readipifc.c diff --git a/src/libip/Darwin.c b/src/libip/Darwin.c new file mode 100644 index 00000000..48c87c62 --- /dev/null +++ b/src/libip/Darwin.c @@ -0,0 +1 @@ +#include "none.c" diff --git a/src/libip/FreeBSD.c b/src/libip/FreeBSD.c new file mode 100644 index 00000000..71fb3ff3 --- /dev/null +++ b/src/libip/FreeBSD.c @@ -0,0 +1,144 @@ +#include +/* #include */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +sockaddr2ip(uchar *ip, struct sockaddr *sa) +{ + struct sockaddr_in *sin; + + sin = (struct sockaddr_in*)sa; + memmove(ip, v4prefix, IPaddrlen); + memmove(ip+IPv4off, &sin->sin_addr, 4); +} + +Ipifc* +readipifc(char *net, Ipifc *ifc, int index) +{ + char *p, *ep, *q; + int i, mib[6], n, alloc; + Ipifc *list, **last; + Iplifc *lifc, **lastlifc; + struct if_msghdr *mh, *nmh; + struct ifa_msghdr *ah; + struct sockaddr *sa; + struct sockaddr_dl *sdl; + uchar ip[IPaddrlen]; + + USED(net); + + free(ifc); + ifc = nil; + list = nil; + last = &list; + + /* + * Does not handle IPv6 yet. + */ + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; + mib[4] = NET_RT_IFLIST; + mib[5] = 0; + + if(sysctl(mib, 6, nil, &n, nil, 0) < 0) + return nil; + p = mallocz(n, 1); + if(p == nil) + return nil; + if(sysctl(mib, 6, p, &n, nil, 0) < 0){ + free(p); + return nil; + } + ep = p+n; + while(p < ep){ + mh = (struct if_msghdr*)p; + p += mh->ifm_msglen; + if(mh->ifm_type != RTM_IFINFO) + continue; + ifc = mallocz(sizeof *ifc, 1); + if(ifc == nil) + break; + *last = ifc; + last = &ifc->next; + sdl = (struct sockaddr_dl*)(mh+1); + n = sdl->sdl_nlen; + if(n >= sizeof ifc->dev) + n = sizeof ifc->dev - 1; + memmove(ifc->dev, sdl->sdl_data, n); + ifc->dev[n] = 0; + ifc->rp.linkmtu = mh->ifm_data.ifi_mtu; + lastlifc = &ifc->lifc; + + while(p < ep){ + ah = (struct ifa_msghdr*)p; + nmh = (struct if_msghdr*)p; + if(nmh->ifm_type != RTM_NEWADDR) + break; + p += nmh->ifm_msglen; + alloc = 0; + for(i=0, q=(char*)(ah+1); iifam_addrs & (1<sa_len+sizeof(long)-1) & ~(sizeof(long)-1); + + if(sa->sa_family == AF_LINK && i == RTAX_IFA){ + struct sockaddr_dl *e; + + if(e->sdl_type == IFT_ETHER && e->sdl_alen == 6) + memmove(ifc->ether, LLADDR(e), 6); + } + if(sa->sa_family != AF_INET) + continue; + if(alloc == 0){ + alloc = 1; + lifc = mallocz(sizeof *lifc, 1); + *lastlifc = lifc; + lastlifc = &lifc->next; + } + sockaddr2ip(ip, sa); + switch(i){ + case RTAX_IFA: + ipmove(lifc->ip, ip); + break; + case RTAX_NETMASK: + memset(ip, 0xFF, IPv4off); + ipmove(lifc->mask, ip); + break; + case RTAX_BRD: + if(mh->ifm_flags & IFF_POINTOPOINT) + /* ipmove(lifc->remote, ip) */ ; + if(mh->ifm_flags & IFF_BROADCAST) + /* ipmove(lifc->bcast, ip) */ ; + break; + case RTAX_GATEWAY: + break; + case RTAX_DST: + break; + } + } + maskip(lifc->ip, lifc->mask, lifc->net); + } + } + return list; +} diff --git a/src/libip/Linux.c b/src/libip/Linux.c new file mode 100644 index 00000000..1419e718 --- /dev/null +++ b/src/libip/Linux.c @@ -0,0 +1,254 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Use netlink sockets to find interfaces. + * Thanks to Erik Quanstrom. + */ +static int +netlinkrequest(int fd, int type, int (*fn)(struct nlmsghdr *h, Ipifc**, int), + Ipifc **ifc, int index) +{ + char buf[1024]; + int n; + struct sockaddr_nl nl; + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + struct nlmsghdr *h; + + memset(&nl, 0, sizeof nl); + nl.nl_family = AF_NETLINK; + + memset(&req, 0, sizeof req); + req.nlh.nlmsg_len = sizeof req; + req.nlh.nlmsg_type = type; + req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = 1; + req.g.rtgen_family = AF_NETLINK; + + if(sendto(fd, (void*)&req, sizeof req, 0, (struct sockaddr*)&nl, sizeof nl) < 0) + return -1; + + while((n=read(fd, buf, sizeof buf)) > 0){ + for(h=(struct nlmsghdr*)buf; NLMSG_OK(h, n); h = NLMSG_NEXT(h, n)){ + if(h->nlmsg_type == NLMSG_DONE) + return 0; + if(h->nlmsg_type == NLMSG_ERROR){ + werrstr("netlink error"); + return -1; + } + if(fn(h, ifc, index) < 0) + return -1; + } + } + werrstr("netlink error"); + return -1; +} + +static int +devsocket(void) +{ + /* we couldn't care less which one; just want to talk to the kernel! */ + static int dumb[3] = { AF_INET, AF_PACKET, AF_INET6 }; + int i, fd; + + for(i=0; i= 0) + return fd; + return -1; +} + +static int +parsertattr(struct rtattr **dst, int ndst, struct nlmsghdr *h, int type, int skip) +{ + struct rtattr *src; + int len; + + len = h->nlmsg_len - NLMSG_LENGTH(skip); + if(len < 0 || h->nlmsg_type != type){ + werrstr("attrs too short"); + return -1; + } + src = (struct rtattr*)((char*)NLMSG_DATA(h) + NLMSG_ALIGN(skip)); + + memset(dst, 0, ndst*sizeof dst[0]); + for(; RTA_OK(src, len); src = RTA_NEXT(src, len)) + if(src->rta_type < ndst) + dst[src->rta_type] = src; + return 0; +} + +static void +rta2ip(int af, uchar *ip, struct rtattr *rta) +{ + memset(ip, 0, IPaddrlen); + + switch(af){ + case AF_INET: + memmove(ip, v4prefix, IPv4off); + memmove(ip+IPv4off, RTA_DATA(rta), IPv4addrlen); + break; + case AF_INET6: + memmove(ip, RTA_DATA(rta), IPaddrlen); + break; + } +} + +static int +getlink(struct nlmsghdr *h, Ipifc **ipifclist, int index) +{ + char *p; + int fd; + struct rtattr *attr[IFLA_MAX+1]; + struct ifinfomsg *ifi; + Ipifc *ifc; + + ifi = (struct ifinfomsg*)NLMSG_DATA(h); + if(index >= 0 && ifi->ifi_index != index) + return 0; + + ifc = mallocz(sizeof *ifc, 1); + if(ifc == nil) + return -1; + ifc->index = ifi->ifi_index; + + while(*ipifclist) + ipifclist = &(*ipifclist)->next; + *ipifclist = ifc; + + if(parsertattr(attr, nelem(attr), h, RTM_NEWLINK, sizeof(struct ifinfomsg)) < 0) + return -1; + + if(attr[IFLA_IFNAME]) + p = (char*)RTA_DATA(attr[IFLA_IFNAME]); + else + p = "nil"; + strecpy(ifc->dev, ifc->dev+sizeof ifc->dev, p); + + if(attr[IFLA_MTU]) + ifc->mtu = *(int*)RTA_DATA(attr[IFLA_MTU]); + + if(attr[IFLA_STATS]){ + struct rtnl_link_stats *s; + + s = RTA_DATA(attr[IFLA_STATS]); + ifc->pktin = s->rx_packets; + ifc->pktout = s->tx_packets; + ifc->errin = s->rx_errors; + ifc->errout = s->tx_errors; + } + + if((fd = devsocket()) > 0){ + struct ifreq ifr; + + memset(&ifr, 0, sizeof ifr); + strncpy(ifr.ifr_name, p, IFNAMSIZ); + ifr.ifr_mtu = 0; + if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0) + ifc->rp.linkmtu = ifr.ifr_mtu; + + memset(&ifr, 0, sizeof ifr); + strncpy(ifr.ifr_name, p, IFNAMSIZ); + if(ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0 + && ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER) + memmove(ifc->ether, ifr.ifr_hwaddr.sa_data, 6); + + close(fd); + } + return 0; +} + +static int +getaddr(struct nlmsghdr *h, Ipifc **ipifclist, int index) +{ + int mask; + Ipifc *ifc; + Iplifc *lifc, **l; + struct ifaddrmsg *ifa; + struct rtattr *attr[IFA_MAX+1]; + + USED(index); + + ifa = (struct ifaddrmsg*)NLMSG_DATA(h); + for(ifc=*ipifclist; ifc; ifc=ifc->next) + if(ifc->index == ifa->ifa_index) + break; + if(ifc == nil) + return 0; + if(parsertattr(attr, nelem(attr), h, RTM_NEWADDR, sizeof(struct ifaddrmsg)) < 0) + return -1; + + lifc = mallocz(sizeof *lifc, 1); + if(lifc == nil) + return -1; + for(l=&ifc->lifc; *l; l=&(*l)->next) + ; + *l = lifc; + + if(attr[IFA_ADDRESS] == nil) + attr[IFA_ADDRESS] = attr[IFA_LOCAL]; + if(attr[IFA_ADDRESS] == nil) + return 0; + + rta2ip(ifa->ifa_family, lifc->ip, attr[IFA_ADDRESS]); + + mask = ifa->ifa_prefixlen/8; + if(ifa->ifa_family == AF_INET) + mask += IPv4off; + memset(lifc->mask, 0xFF, mask); + memmove(lifc->net, lifc->ip, mask); + + if(attr[IFA_CACHEINFO]){ + struct ifa_cacheinfo *ci; + + ci = RTA_DATA(attr[IFA_CACHEINFO]); + lifc->preflt = ci->ifa_prefered; + lifc->validlt = ci->ifa_valid; + } + return 0; +} + +Ipifc* +readipifc(char *net, Ipifc *ifc, int index) +{ + int fd; + + USED(net); + freeipifc(ifc); + ifc = nil; + + fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if(fd < 0) + return nil; + ifc = nil; + if(netlinkrequest(fd, RTM_GETLINK, getlink, &ifc, index) < 0 + || netlinkrequest(fd, RTM_GETADDR, getaddr, &ifc, index) < 0){ + close(fd); + freeipifc(ifc); + return nil; + } + close(fd); + return ifc; +} + +int +_myetheraddr(uchar *to, char *dev) +{ + int fd; + struct ifreq ifr; + + return 0; +} diff --git a/src/libip/NetBSD.c b/src/libip/NetBSD.c new file mode 100644 index 00000000..48c87c62 --- /dev/null +++ b/src/libip/NetBSD.c @@ -0,0 +1 @@ +#include "none.c" diff --git a/src/libip/OpenBSD.c b/src/libip/OpenBSD.c new file mode 100644 index 00000000..48c87c62 --- /dev/null +++ b/src/libip/OpenBSD.c @@ -0,0 +1 @@ +#include "none.c" diff --git a/src/libip/SunOS.c b/src/libip/SunOS.c new file mode 100644 index 00000000..48c87c62 --- /dev/null +++ b/src/libip/SunOS.c @@ -0,0 +1 @@ +#include "none.c" diff --git a/src/libip/freeipifc.c b/src/libip/freeipifc.c new file mode 100644 index 00000000..7899facc --- /dev/null +++ b/src/libip/freeipifc.c @@ -0,0 +1,20 @@ +#include +#include +#include + +void +freeipifc(Ipifc *i) +{ + Ipifc *next; + Iplifc *l, *lnext; + + for(; i; i=next){ + next = i->next; + for(l=i->lifc; l; l=lnext){ + lnext = l->next; + free(l); + } + free(i); + } +} + diff --git a/src/libip/mkfile b/src/libip/mkfile index 98496738..35399d71 100644 --- a/src/libip/mkfile +++ b/src/libip/mkfile @@ -5,14 +5,14 @@ OFILES=\ bo.$O\ classmask.$O\ eipfmt.$O\ + freeipifc.$O\ ipaux.$O\ - myetheraddr.$O\ myipaddr.$O\ parseether.$O\ parseip.$O\ ptclbsum.$O\ - readipifc.$O\ udp.$O\ + $SYSNAME.$O\ HFILES=\ ip.h diff --git a/src/libip/myetheraddr.c b/src/libip/myetheraddr.c index d6995b7a..a51a40d6 100644 --- a/src/libip/myetheraddr.c +++ b/src/libip/myetheraddr.c @@ -2,40 +2,25 @@ #include #include +static char zea[6]; + int myetheraddr(uchar *to, char *dev) { - int n, fd; - char buf[256], *ptr; - - /* Make one exist */ - if(*dev == '/') - sprint(buf, "%s/clone", dev); - else - sprint(buf, "/net/%s/clone", dev); - fd = open(buf, ORDWR); - if(fd >= 0) - close(fd); - - if(*dev == '/') - sprint(buf, "%s/0/stats", dev); - else - sprint(buf, "/net/%s/0/stats", dev); - fd = open(buf, OREAD); - if(fd < 0) - return -1; - - n = read(fd, buf, sizeof(buf)-1); - close(fd); - if(n <= 0) - return -1; - buf[n] = 0; - - ptr = strstr(buf, "addr: "); - if(!ptr) - return -1; - ptr += 6; - - parseether(to, ptr); - return 0; + Ipifc *ifclist, *ifc; + + ifclist = readipifc(nil, nil, -1); + for(ifc=ifclist; ifc; ifc=ifc->next){ + if(dev && strcmp(ifc->dev) != 0) + continue; + if(memcmp(zea, ifc->ether, 6) == 0) + continue; + memmove(to, ifc->ether, 6); + freeipifc(ifclist); + return 0; + } + freeipifc(ifclist); + werrstr("no ethernet devices"); + return -1; } + diff --git a/src/libip/myipaddr.c b/src/libip/myipaddr.c index d9b69201..a7149ffa 100644 --- a/src/libip/myipaddr.c +++ b/src/libip/myipaddr.c @@ -2,20 +2,44 @@ #include #include +static uchar loopbacknet[IPaddrlen] = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0xff, 0xff, + 127, 0, 0, 0 +}; +static uchar loopbackmask[IPaddrlen] = { + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0, 0, 0 +}; + +// find first ip addr that isn't the friggin loopback address +// unless there are no others int myipaddr(uchar *ip, char *net) { Ipifc *nifc; Iplifc *lifc; - static Ipifc *ifc; + Ipifc *ifc; + uchar mynet[IPaddrlen]; - ifc = readipifc(net, ifc, -1); + ifc = readipifc(net, nil, -1); for(nifc = ifc; nifc; nifc = nifc->next) - for(lifc = nifc->lifc; lifc; lifc = lifc->next) + for(lifc = nifc->lifc; lifc; lifc = lifc->next){ + maskip(lifc->ip, loopbackmask, mynet); + if(ipcmp(mynet, loopbacknet) == 0){ + continue; + } if(ipcmp(lifc->ip, IPnoaddr) != 0){ ipmove(ip, lifc->ip); + freeipifc(ifc); return 0; } + } ipmove(ip, IPnoaddr); + freeipifc(ifc); return -1; } + diff --git a/src/libip/none.c b/src/libip/none.c new file mode 100644 index 00000000..20c04c67 --- /dev/null +++ b/src/libip/none.c @@ -0,0 +1,24 @@ +#include +#include +#include + +Ipifc* +readipifc(char *net, Ipifc *ipifc, int index) +{ + USED(net); + USED(ipifc); + USED(index); + + werrstr("not implemented"); + return nil; +} + +int +myetheraddr(uchar *to, char *dev) +{ + USED(to); + USED(dev); + + werrstr("not implemented"); + return -1; +} diff --git a/src/libip/readipifc.c b/src/libip/readipifc.c deleted file mode 100644 index b28b3b0c..00000000 --- a/src/libip/readipifc.c +++ /dev/null @@ -1,194 +0,0 @@ -#include -#include -#include -#include - -static Ipifc** -_readoldipifc(char *buf, Ipifc **l, int index) -{ - char *f[200]; - int i, n; - Ipifc *ifc; - Iplifc *lifc, **ll; - - /* allocate new interface */ - *l = ifc = mallocz(sizeof(Ipifc), 1); - if(ifc == nil) - return l; - l = &ifc->next; - ifc->index = index; - - n = tokenize(buf, f, nelem(f)); - if(n < 2) - return l; - - strncpy(ifc->dev, f[0], sizeof ifc->dev); - ifc->dev[sizeof(ifc->dev) - 1] = 0; - ifc->mtu = strtoul(f[1], nil, 10); - - ll = &ifc->lifc; - for(i = 2; n-i >= 7; i += 7){ - /* allocate new local address */ - *ll = lifc = mallocz(sizeof(Iplifc), 1); - ll = &lifc->next; - - parseip(lifc->ip, f[i]); - parseipmask(lifc->mask, f[i+1]); - parseip(lifc->net, f[i+2]); - ifc->pktin = strtoul(f[i+3], nil, 10); - ifc->pktout = strtoul(f[i+4], nil, 10); - ifc->errin = strtoul(f[i+5], nil, 10); - ifc->errout = strtoul(f[i+6], nil, 10); - } - return l; -} - -static char* -findfield(char *name, char **f, int n) -{ - int i; - - for(i = 0; i < n-1; i++) - if(strcmp(f[i], name) == 0) - return f[i+1]; - return ""; -} - -static Ipifc** -_readipifc(char *file, Ipifc **l, int index) -{ - int i, n, fd, lines; - char buf[4*1024]; - char *line[32]; - char *f[64]; - Ipifc *ifc; - Iplifc *lifc, **ll; - - /* read the file */ - fd = open(file, OREAD); - if(fd < 0) - return l; - n = 0; - while((i = read(fd, buf+n, sizeof(buf)-1-n)) > 0 && n < sizeof(buf) - 1) - n += i; - buf[n] = 0; - close(fd); - - if(strncmp(buf, "device", 6) != 0) - return _readoldipifc(buf, l, index); - - /* allocate new interface */ - *l = ifc = mallocz(sizeof(Ipifc), 1); - if(ifc == nil) - return l; - l = &ifc->next; - ifc->index = index; - - lines = getfields(buf, line, nelem(line), 1, "\n"); - - /* pick off device specific info(first line) */ - n = tokenize(line[0], f, nelem(f)); - strncpy(ifc->dev, findfield("device", f, n), sizeof(ifc->dev)); - ifc->dev[sizeof(ifc->dev)-1] = 0; - if(ifc->dev[0] == 0){ - free(ifc); - return l; - } - ifc->mtu = strtoul(findfield("maxmtu", f, n), nil, 10); - ifc->sendra6 = atoi(findfield("sendra", f, n)); - ifc->recvra6 = atoi(findfield("recvra", f, n)); - ifc->rp.mflag = atoi(findfield("mflag", f, n)); - ifc->rp.oflag = atoi(findfield("oflag", f, n)); - ifc->rp.maxraint = atoi(findfield("maxraint", f, n)); - ifc->rp.minraint = atoi(findfield("minraint", f, n)); - ifc->rp.linkmtu = atoi(findfield("linkmtu", f, n)); - ifc->rp.reachtime = atoi(findfield("reachtime", f, n)); - ifc->rp.rxmitra = atoi(findfield("rxmitra", f, n)); - ifc->rp.ttl = atoi(findfield("ttl", f, n)); - ifc->rp.routerlt = atoi(findfield("routerlt", f, n)); - ifc->pktin = strtoul(findfield("pktin", f, n), nil, 10); - ifc->pktout = strtoul(findfield("pktout", f, n), nil, 10); - ifc->errin = strtoul(findfield("errin", f, n), nil, 10); - ifc->errout = strtoul(findfield("errout", f, n), nil, 10); - - /* now read the addresses */ - ll = &ifc->lifc; - for(i = 1; i < lines; i++){ - n = tokenize(line[i], f, nelem(f)); - if(n < 5) - break; - - /* allocate new local address */ - *ll = lifc = mallocz(sizeof(Iplifc), 1); - ll = &lifc->next; - - parseip(lifc->ip, f[0]); - parseipmask(lifc->mask, f[1]); - parseip(lifc->net, f[2]); - - lifc->validlt = strtoul(f[3], nil, 10); - lifc->preflt = strtoul(f[4], nil, 10); - } - - return l; -} - -static void -_freeifc(Ipifc *ifc) -{ - Ipifc *next; - Iplifc *lnext, *lifc; - - if(ifc == nil) - return; - for(; ifc; ifc = next){ - next = ifc->next; - for(lifc = ifc->lifc; lifc; lifc = lnext){ - lnext = lifc->next; - free(lifc); - } - free(ifc); - } -} - -Ipifc* -readipifc(char *net, Ipifc *ifc, int index) -{ - int fd, i, n; - Dir *dir; - char directory[128]; - char buf[128]; - Ipifc **l; - - _freeifc(ifc); - - l = &ifc; - ifc = nil; - - if(net == 0) - net = "/net"; - snprint(directory, sizeof(directory), "%s/ipifc", net); - - if(index >= 0){ - snprint(buf, sizeof(buf), "%s/%d/status", directory, index); - _readipifc(buf, l, index); - } else { - fd = open(directory, OREAD); - if(fd < 0) - return nil; - n = dirreadall(fd, &dir); - close(fd); - - for(i = 0; i < n; i++){ - if(strcmp(dir[i].name, "clone") == 0) - continue; - if(strcmp(dir[i].name, "stats") == 0) - continue; - snprint(buf, sizeof(buf), "%s/%s/status", directory, dir[i].name); - l = _readipifc(buf, l, atoi(dir[i].name)); - } - free(dir); - } - - return ifc; -} -- cgit v1.2.3