📄 intf.c
字号:
/* * intf.c * * Copyright (c) 2001 Dug Song <dugsong@monkey.org> * * $Id: intf.c,v 1.55 2005/02/10 16:57:35 dugsong Exp $ */#ifdef _WIN32#include "dnet_winconfig.h"#else#include "config.h"#endif#include <sys/param.h>#include <sys/types.h>#include <sys/ioctl.h>#include <sys/socket.h>#ifdef HAVE_SYS_SOCKIO_H# include <sys/sockio.h>#endif/* XXX - AIX */#ifndef IP_MULTICAST# define IP_MULTICAST#endif#include <net/if.h>#ifdef HAVE_NET_IF_VAR_H# include <net/if_var.h>#endif#undef IP_MULTICAST/* XXX - IPv6 ioctls */#ifdef HAVE_NETINET_IN_VAR_H# include <netinet/in.h># include <netinet/in_var.h>#endif#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include "dnet.h"/* XXX - Tru64 */#if defined(SIOCRIPMTU) && defined(SIOCSIPMTU)# define SIOCGIFMTU SIOCRIPMTU# define SIOCSIFMTU SIOCSIPMTU#endif/* XXX - HP-UX */#if defined(SIOCADDIFADDR) && defined(SIOCDELIFADDR)# define SIOCAIFADDR SIOCADDIFADDR# define SIOCDIFADDR SIOCDELIFADDR#endif/* XXX - HP-UX, Solaris */#if !defined(ifr_mtu) && defined(ifr_metric)# define ifr_mtu ifr_metric#endif#ifdef HAVE_SOCKADDR_SA_LEN# define NEXTIFR(i) ((struct ifreq *)((u_char *)&i->ifr_addr + \ (i->ifr_addr.sa_len ? i->ifr_addr.sa_len : \ sizeof(i->ifr_addr))))#else# define NEXTIFR(i) (i + 1)#endif/* XXX - superset of ifreq, for portable SIOC{A,D}IFADDR */struct dnet_ifaliasreq { char ifra_name[IFNAMSIZ]; struct sockaddr ifra_addr; struct sockaddr ifra_brdaddr; struct sockaddr ifra_mask; int ifra_cookie; /* XXX - IRIX!@#$ */};struct intf_handle { int fd; int fd6; struct ifconf ifc; u_char ifcbuf[4192];};static intintf_flags_to_iff(u_short flags, int iff){ if (flags & INTF_FLAG_UP) iff |= IFF_UP; else iff &= ~IFF_UP; if (flags & INTF_FLAG_NOARP) iff |= IFF_NOARP; else iff &= ~IFF_NOARP; return (iff);}static u_intintf_iff_to_flags(int iff){ u_int n = 0; if (iff & IFF_UP) n |= INTF_FLAG_UP; if (iff & IFF_LOOPBACK) n |= INTF_FLAG_LOOPBACK; if (iff & IFF_POINTOPOINT) n |= INTF_FLAG_POINTOPOINT; if (iff & IFF_NOARP) n |= INTF_FLAG_NOARP; if (iff & IFF_BROADCAST) n |= INTF_FLAG_BROADCAST; if (iff & IFF_MULTICAST) n |= INTF_FLAG_MULTICAST; return (n);}intf_t *intf_open(void){ intf_t *intf; int one = 1; if ((intf = calloc(1, sizeof(*intf))) != NULL) { intf->fd = intf->fd6 = -1; if ((intf->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return (intf_close(intf)); setsockopt(intf->fd, SOL_SOCKET, SO_BROADCAST, (const char *) &one, sizeof(one));#ifdef SIOCGIFNETMASK_IN6 if ((intf->fd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {# ifdef EPROTONOSUPPORT if (errno != EPROTONOSUPPORT)# endif return (intf_close(intf)); }#endif } return (intf);}static int_intf_delete_addrs(intf_t *intf, struct intf_entry *entry){#if defined(SIOCDIFADDR) struct dnet_ifaliasreq ifra; memset(&ifra, 0, sizeof(ifra)); strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name)); if (entry->intf_addr.addr_type == ADDR_TYPE_IP) { addr_ntos(&entry->intf_addr, &ifra.ifra_addr); ioctl(intf->fd, SIOCDIFADDR, &ifra); } if (entry->intf_dst_addr.addr_type == ADDR_TYPE_IP) { addr_ntos(&entry->intf_dst_addr, &ifra.ifra_addr); ioctl(intf->fd, SIOCDIFADDR, &ifra); }#elif defined(SIOCLIFREMOVEIF) struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name)); /* XXX - overloading Solaris lifreq with ifreq */ ioctl(intf->fd, SIOCLIFREMOVEIF, &ifr);#endif return (0);}static int_intf_delete_aliases(intf_t *intf, struct intf_entry *entry){ int i;#if defined(SIOCDIFADDR) && !defined(__linux__) /* XXX - see Linux below */ struct dnet_ifaliasreq ifra; memset(&ifra, 0, sizeof(ifra)); strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name)); for (i = 0; i < (int)entry->intf_alias_num; i++) { addr_ntos(&entry->intf_alias_addrs[i], &ifra.ifra_addr); ioctl(intf->fd, SIOCDIFADDR, &ifra); }#else struct ifreq ifr; for (i = 0; i < entry->intf_alias_num; i++) { snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s:%d", entry->intf_name, i + 1);# ifdef SIOCLIFREMOVEIF /* XXX - overloading Solaris lifreq with ifreq */ ioctl(intf->fd, SIOCLIFREMOVEIF, &ifr);# else /* XXX - only need to set interface down on Linux */ ifr.ifr_flags = 0; ioctl(intf->fd, SIOCSIFFLAGS, &ifr);# endif }#endif return (0);}static int_intf_add_aliases(intf_t *intf, const struct intf_entry *entry){ int i;#ifdef SIOCAIFADDR struct dnet_ifaliasreq ifra; struct addr bcast; memset(&ifra, 0, sizeof(ifra)); strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name)); for (i = 0; i < (int)entry->intf_alias_num; i++) { if (entry->intf_alias_addrs[i].addr_type != ADDR_TYPE_IP) continue; if (addr_ntos(&entry->intf_alias_addrs[i], &ifra.ifra_addr) < 0) return (-1); addr_bcast(&entry->intf_alias_addrs[i], &bcast); addr_ntos(&bcast, &ifra.ifra_brdaddr); addr_btos(entry->intf_alias_addrs[i].addr_bits, &ifra.ifra_mask); if (ioctl(intf->fd, SIOCAIFADDR, &ifra) < 0) return (-1); }#else struct ifreq ifr; int n = 1; for (i = 0; i < entry->intf_alias_num; i++) { if (entry->intf_alias_addrs[i].addr_type != ADDR_TYPE_IP) continue; snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s:%d", entry->intf_name, n++);# ifdef SIOCLIFADDIF if (ioctl(intf->fd, SIOCLIFADDIF, &ifr) < 0) return (-1);# endif if (addr_ntos(&entry->intf_alias_addrs[i], &ifr.ifr_addr) < 0) return (-1); if (ioctl(intf->fd, SIOCSIFADDR, &ifr) < 0) return (-1); } strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name));#endif return (0);}intintf_set(intf_t *intf, const struct intf_entry *entry){ struct ifreq ifr; struct intf_entry *orig; struct addr bcast; u_char buf[BUFSIZ]; orig = (struct intf_entry *)buf; orig->intf_len = sizeof(buf); strcpy(orig->intf_name, entry->intf_name); if (intf_get(intf, orig) < 0) return (-1); /* Delete any existing aliases. */ if (_intf_delete_aliases(intf, orig) < 0) return (-1); /* Delete any existing addrs. */ if (_intf_delete_addrs(intf, orig) < 0) return (-1); memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name)); /* Set interface MTU. */ if (entry->intf_mtu != 0) { ifr.ifr_mtu = entry->intf_mtu;#ifdef SIOCSIFMTU if (ioctl(intf->fd, SIOCSIFMTU, &ifr) < 0)#endif return (-1); } /* Set interface address. */ if (entry->intf_addr.addr_type == ADDR_TYPE_IP) {#ifdef BSD /* XXX - why must this happen before SIOCSIFADDR? */ if (addr_btos(entry->intf_addr.addr_bits, &ifr.ifr_addr) == 0) { if (ioctl(intf->fd, SIOCSIFNETMASK, &ifr) < 0) return (-1); }#endif if (addr_ntos(&entry->intf_addr, &ifr.ifr_addr) < 0) return (-1); if (ioctl(intf->fd, SIOCSIFADDR, &ifr) < 0 && errno != EEXIST) return (-1); if (addr_btos(entry->intf_addr.addr_bits, &ifr.ifr_addr) == 0#ifdef __linux__ && entry->intf_addr.addr_ip != 0#endif ) { if (ioctl(intf->fd, SIOCSIFNETMASK, &ifr) < 0) return (-1); } if (addr_bcast(&entry->intf_addr, &bcast) == 0) { if (addr_ntos(&bcast, &ifr.ifr_broadaddr) == 0) { /* XXX - ignore error from non-broadcast ifs */ ioctl(intf->fd, SIOCSIFBRDADDR, &ifr); } } } /* Set link-level address. */ if (entry->intf_link_addr.addr_type == ADDR_TYPE_ETH && addr_cmp(&entry->intf_link_addr, &orig->intf_link_addr) != 0) {#if defined(SIOCSIFHWADDR) if (addr_ntos(&entry->intf_link_addr, &ifr.ifr_hwaddr) < 0) return (-1); if (ioctl(intf->fd, SIOCSIFHWADDR, &ifr) < 0) return (-1);#elif defined (SIOCSIFLLADDR) memcpy(ifr.ifr_addr.sa_data, &entry->intf_link_addr.addr_eth, ETH_ADDR_LEN); ifr.ifr_addr.sa_len = ETH_ADDR_LEN; if (ioctl(intf->fd, SIOCSIFLLADDR, &ifr) < 0) return (-1);#else eth_t *eth; if ((eth = eth_open(entry->intf_name)) == NULL) return (-1); if (eth_set(eth, &entry->intf_link_addr.addr_eth) < 0) { eth_close(eth); return (-1); } eth_close(eth);#endif } /* Set point-to-point destination. */ if (entry->intf_dst_addr.addr_type == ADDR_TYPE_IP) { if (addr_ntos(&entry->intf_dst_addr, &ifr.ifr_dstaddr) < 0) return (-1); if (ioctl(intf->fd, SIOCSIFDSTADDR, &ifr) < 0 && errno != EEXIST) return (-1); } /* Add aliases. */ if (_intf_add_aliases(intf, entry) < 0) return (-1); /* Set interface flags. */ if (ioctl(intf->fd, SIOCGIFFLAGS, &ifr) < 0) return (-1); ifr.ifr_flags = intf_flags_to_iff(entry->intf_flags, ifr.ifr_flags); if (ioctl(intf->fd, SIOCSIFFLAGS, &ifr) < 0) return (-1); return (0);}/* XXX - this is total crap. how to do this without walking ifnet? */static void_intf_set_type(struct intf_entry *entry){ if ((entry->intf_flags & INTF_FLAG_BROADCAST) != 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -