1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-28 10:29:03 +00:00

SIOCGLIFCONF-based implementation of intf_loop for Solaris 10.

The SIOCG*L*IFCONF interface is mostly like SIOCGIFCONF except that it
uses a sockaddr_storage-based structure that allows handling IPv6 interfaces.
This commit is contained in:
david
2011-09-30 00:42:45 +00:00
parent 0e15793e7f
commit dbf79dafaa

View File

@@ -71,6 +71,8 @@
# define NEXTIFR(i) (i + 1)
#endif
#define NEXTLIFR(i) (i + 1)
/* XXX - superset of ifreq, for portable SIOC{A,D}IFADDR */
struct dnet_ifaliasreq {
char ifra_name[IFNAMSIZ];
@@ -84,6 +86,9 @@ struct intf_handle {
int fd;
int fd6;
struct ifconf ifc;
#ifdef SIOCGLIFCONF
struct lifconf lifc;
#endif
u_char ifcbuf[4192];
};
@@ -388,6 +393,66 @@ _intf_set_type(struct intf_entry *entry)
entry->intf_type = INTF_TYPE_OTHER;
}
#ifdef SIOCGLIFCONF
int
_intf_get_noalias(intf_t *intf, struct intf_entry *entry)
{
struct lifreq lifr;
/* Get interface index. */
entry->intf_index = if_nametoindex(entry->intf_name);
if (entry->intf_index == 0)
return (-1);
strlcpy(lifr.lifr_name, entry->intf_name, sizeof(lifr.lifr_name));
/* Get interface flags. */
if (ioctl(intf->fd, SIOCGLIFFLAGS, &lifr) < 0)
return (-1);
entry->intf_flags = intf_iff_to_flags(lifr.lifr_flags);
_intf_set_type(entry);
/* Get interface MTU. */
#ifdef SIOCSIFMTU
if (ioctl(intf->fd, SIOCGLIFMTU, &lifr) < 0)
#endif
return (-1);
entry->intf_mtu = lifr.lifr_mtu;
entry->intf_addr.addr_type = entry->intf_dst_addr.addr_type =
entry->intf_link_addr.addr_type = ADDR_TYPE_NONE;
/* Get primary interface address. */
if (ioctl(intf->fd, SIOCGLIFADDR, &lifr) == 0) {
addr_ston((struct sockaddr *)&lifr.lifr_addr, &entry->intf_addr);
if (ioctl(intf->fd, SIOCGLIFNETMASK, &lifr) < 0)
return (-1);
addr_stob((struct sockaddr *)&lifr.lifr_addr, &entry->intf_addr.addr_bits);
}
/* Get other addresses. */
if (entry->intf_type == INTF_TYPE_TUN) {
if (ioctl(intf->fd, SIOCGLIFDSTADDR, &lifr) == 0) {
if (addr_ston((struct sockaddr *)&lifr.lifr_addr,
&entry->intf_dst_addr) < 0)
return (-1);
}
} else if (entry->intf_type == INTF_TYPE_ETH) {
eth_t *eth;
if ((eth = eth_open(entry->intf_name)) != NULL) {
if (!eth_get(eth, &entry->intf_link_addr.addr_eth)) {
entry->intf_link_addr.addr_type =
ADDR_TYPE_ETH;
entry->intf_link_addr.addr_bits =
ETH_ADDR_BITS;
}
eth_close(eth);
}
}
return (0);
}
#else
static int
_intf_get_noalias(intf_t *intf, struct intf_entry *entry)
{
@@ -461,6 +526,7 @@ _intf_get_noalias(intf_t *intf, struct intf_entry *entry)
}
return (0);
}
#endif
#ifdef SIOCLIFADDR
/* XXX - aliases on IRIX don't show up in SIOCGIFCONF */
@@ -489,6 +555,68 @@ _intf_get_aliases(intf_t *intf, struct intf_entry *entry)
return (0);
}
#elif defined(SIOCGLIFCONF)
static int
_intf_get_aliases(intf_t *intf, struct intf_entry *entry)
{
struct lifreq *lifr, *llifr;
struct lifreq tmplifr;
struct addr *ap, *lap;
char *p;
if (intf->lifc.lifc_len < (int)sizeof(*lifr)) {
errno = EINVAL;
return (-1);
}
entry->intf_alias_num = 0;
ap = entry->intf_alias_addrs;
llifr = (struct lifreq *)intf->lifc.lifc_buf +
(intf->lifc.lifc_len / sizeof(*llifr));
lap = (struct addr *)((u_char *)entry + entry->intf_len);
/* Get addresses for this interface. */
for (lifr = intf->lifc.lifc_req; lifr < llifr && (ap + 1) < lap;
lifr = NEXTLIFR(lifr)) {
/* XXX - Linux, Solaris ifaliases */
if ((p = strchr(lifr->lifr_name, ':')) != NULL)
*p = '\0';
if (strcmp(lifr->lifr_name, entry->intf_name) != 0) {
if (p) *p = ':';
continue;
}
/* Fix the name back up */
if (p) *p = ':';
if (addr_ston((struct sockaddr *)&lifr->lifr_addr, ap) < 0)
continue;
/* XXX */
if (ap->addr_type == ADDR_TYPE_ETH) {
memcpy(&entry->intf_link_addr, ap, sizeof(*ap));
continue;
} else if (ap->addr_type == ADDR_TYPE_IP) {
if (ap->addr_ip == entry->intf_addr.addr_ip ||
ap->addr_ip == entry->intf_dst_addr.addr_ip)
continue;
strlcpy(tmplifr.lifr_name, lifr->lifr_name, sizeof(tmplifr.lifr_name));
if (ioctl(intf->fd, SIOCGIFNETMASK, &tmplifr) == 0)
addr_stob((struct sockaddr *)&tmplifr.lifr_addr, &ap->addr_bits);
} else if (ap->addr_type == ADDR_TYPE_IP6 && intf->fd6 != -1) {
strlcpy(tmplifr.lifr_name, lifr->lifr_name, sizeof(tmplifr.lifr_name));
if (ioctl(intf->fd, SIOCGLIFNETMASK, &tmplifr) == 0) {
addr_stob((struct sockaddr *)&tmplifr.lifr_addr,
&ap->addr_bits);
}
else perror("SIOCGLIFNETMASK");
}
ap++, entry->intf_alias_num++;
}
entry->intf_len = (u_char *)ap - (u_char *)entry;
return (0);
}
#else
static int
_intf_get_aliases(intf_t *intf, struct intf_entry *entry)
@@ -753,6 +881,55 @@ intf_loop(intf_t *intf, intf_handler callback, void *arg)
return (ret);
}
#elif defined(SIOCGLIFCONF)
int
intf_loop(intf_t *intf, intf_handler callback, void *arg)
{
struct intf_entry *entry;
struct lifreq *lifr, *llifr, *plifr;
char *p, ebuf[BUFSIZ];
int ret;
entry = (struct intf_entry *)ebuf;
intf->lifc.lifc_buf = (caddr_t)intf->ifcbuf;
intf->lifc.lifc_len = sizeof(intf->ifcbuf);
if (ioctl(intf->fd, SIOCGLIFCONF, &intf->lifc) < 0)
return (-1);
llifr = (struct lifreq *)&intf->lifc.lifc_buf[intf->lifc.lifc_len];
for (lifr = intf->lifc.lifc_req; lifr < llifr; lifr = NEXTLIFR(lifr)) {
/* XXX - Linux, Solaris ifaliases */
if ((p = strchr(lifr->lifr_name, ':')) != NULL)
*p = '\0';
for (plifr = intf->lifc.lifc_req; plifr < lifr; plifr = NEXTLIFR(lifr)) {
if (strcmp(lifr->lifr_name, plifr->lifr_name) == 0)
break;
}
if (lifr > intf->lifc.lifc_req && plifr < llifr)
continue;
memset(ebuf, 0, sizeof(ebuf));
strlcpy(entry->intf_name, lifr->lifr_name,
sizeof(entry->intf_name));
entry->intf_len = sizeof(ebuf);
/* Repair the alias name back up */
if (p) *p = ':';
if (_intf_get_noalias(intf, entry) < 0)
return (-1);
if (_intf_get_aliases(intf, entry) < 0)
return (-1);
if ((ret = (*callback)(entry, arg)) != 0)
return (ret);
}
return (0);
}
#else
int
intf_loop(intf_t *intf, intf_handler callback, void *arg)