您尚未登录。

楼主 # 2023-03-15 10:37:46

uuid
会员
注册时间: 2020-12-08
已发帖子: 45
积分: 31

C 网络编程

https://stackoverflow.com/questions/4951257/using-c-code-to-get-same-info-as-ifconfig

#include <stdio.h>
#include <unistd.h>
#include <string.h> /* for strncpy */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>

void parse_ioctl(const char *ifname)
{
    printf("%s\n", "scarf rosari...");
    int sock;
    struct ifreq ifr;
    struct sockaddr_in *ipaddr;
    char address[INET_ADDRSTRLEN];
    size_t ifnamelen;

    /* copy ifname to ifr object */
    ifnamelen = strlen(ifname);
    if (ifnamelen >= sizeof(ifr.ifr_name)) {
        printf("error :%s\n", ifr.ifr_name);
        return ;
    }
    memcpy(ifr.ifr_name, ifname, ifnamelen);
    ifr.ifr_name[ifnamelen] = '\0';

    /* open socket */
    sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (sock < 0) {
        printf("error :%s\n", "unable to open socket..");
        return;
    }

    /* process mac */
    if (ioctl(sock, SIOCGIFHWADDR, &ifr) != -1) {
        printf("Mac address: %02x:%02x:%02x:%02x:%02x:%02x\n",
                (unsigned char)ifr.ifr_hwaddr.sa_data[0],
                (unsigned char)ifr.ifr_hwaddr.sa_data[1],
                (unsigned char)ifr.ifr_hwaddr.sa_data[2],
                (unsigned char)ifr.ifr_hwaddr.sa_data[3],
                (unsigned char)ifr.ifr_hwaddr.sa_data[4],
                (unsigned char)ifr.ifr_hwaddr.sa_data[5]);
    }

    /* process mtu */
    if (ioctl(sock, SIOCGIFMTU, &ifr) != -1) {
        printf("MTU: %d\n", ifr.ifr_mtu);
    }

    /* die if cannot get address */
    if (ioctl(sock, SIOCGIFADDR, &ifr) == -1) {
        close(sock);
        return;
    }

    /* process ip */
    ipaddr = (struct sockaddr_in *)&ifr.ifr_addr;
    if (inet_ntop(AF_INET, &ipaddr->sin_addr, address, sizeof(address)) != NULL) {
        printf("Ip address: %s\n", address);
    }

    /* try to get broadcast */
    if (ioctl(sock, SIOCGIFBRDADDR, &ifr) != -1) {
        ipaddr = (struct sockaddr_in *)&ifr.ifr_broadaddr;
        if (inet_ntop(AF_INET, &ipaddr->sin_addr, address, sizeof(address)) != NULL) {
            printf("Broadcast: %s\n", address);
        }
    }

    /* try to get mask */
    if (ioctl(sock, SIOCGIFNETMASK, &ifr) != -1) {
        ipaddr = (struct sockaddr_in *)&ifr.ifr_netmask;
        if (inet_ntop(AF_INET, &ipaddr->sin_addr, address, sizeof(address)) != NULL) {
            printf("Netmask: %s\n", address);
        }
    }

    close(sock);
}

int main()
{
        parse_ioctl("eth0");
}
$ ./getip2
scarf rosari...
Mac address: 00:0c:29:0e:eb:92
MTU: 1500
Ip address: 192.168.80.178
Broadcast: 192.168.80.255
Netmask: 255.255.255.0

离线

楼主 #1 2023-03-15 10:48:00

uuid
会员
注册时间: 2020-12-08
已发帖子: 45
积分: 31

Re: C 网络编程

获取网关地址:

$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.80.2    0.0.0.0         UG    100    0        0 ens33
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.80.0    0.0.0.0         255.255.255.0   U     100    0        0 ens33
$ route -n |grep ens33 | grep 'UG[ \t]' | awk '{print $2}'
192.168.80.2

https://stackoverflow.com/questions/3288065/getting-gateway-to-use-for-a-given-ip-in-ansi-c

char* GetGatewayForInterface(const char* interface) 
{
    char* gateway = NULL;

    char cmd [1000] = {0x0};
    sprintf(cmd,"route -n | grep %s  | grep 'UG[ \t]' | awk '{print $2}'", interface);
    FILE* fp = popen(cmd, "r");
    char line[256]={0x0};

    if(fgets(line, sizeof(line), fp) != NULL)
        gateway = string(line);


    pclose(fp);
}

离线

楼主 #2 2023-03-15 10:51:34

uuid
会员
注册时间: 2020-12-08
已发帖子: 45
积分: 31

Re: C 网络编程

或者用另外一个方法:

This is OS specific, there's no unified(or ANSI C) API for this.

Assuming Linux, the best way is to just parse /proc/net/route , look for the entry where Destination is 00000000 , the default gateway is in the Gateway column , where you can read the hex representation of the gateway IP address (in big endian , I believe)

If you want to do this via more specific API calls, you'll have to go through quite some hoops, here's an example program:



https://stackoverflow.com/questions/3288065/getting-gateway-to-use-for-a-given-ip-in-ansi-c


#include <netinet/in.h>
#include <net/if.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>


#define BUFSIZE 8192
char gateway[255];

struct route_info {
    struct in_addr dstAddr;
    struct in_addr srcAddr;
    struct in_addr gateWay;
    char ifName[IF_NAMESIZE];
};

int readNlSock(int sockFd, char *bufPtr, int seqNum, int pId)
{
    struct nlmsghdr *nlHdr;
    int readLen = 0, msgLen = 0;

 do {
    /* Recieve response from the kernel */
        if ((readLen = recv(sockFd, bufPtr, BUFSIZE - msgLen, 0)) < 0) {
            perror("SOCK READ: ");
            return -1;
        }

        nlHdr = (struct nlmsghdr *) bufPtr;

    /* Check if the header is valid */
        if ((NLMSG_OK(nlHdr, readLen) == 0)
            || (nlHdr->nlmsg_type == NLMSG_ERROR)) {
            perror("Error in recieved packet");
            return -1;
        }

    /* Check if the its the last message */
        if (nlHdr->nlmsg_type == NLMSG_DONE) {
            break;
        } else {
    /* Else move the pointer to buffer appropriately */
            bufPtr += readLen;
            msgLen += readLen;
        }

    /* Check if its a multi part message */
        if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) {
           /* return if its not */
            break;
        }
    } while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pId));
    return msgLen;
}
/* For printing the routes. */
void printRoute(struct route_info *rtInfo)
{
    char tempBuf[512];

/* Print Destination address */
    if (rtInfo->dstAddr.s_addr != 0)
        strcpy(tempBuf,  inet_ntoa(rtInfo->dstAddr));
    else
        sprintf(tempBuf, "*.*.*.*\t");
    fprintf(stdout, "%s\t", tempBuf);

/* Print Gateway address */
    if (rtInfo->gateWay.s_addr != 0)
        strcpy(tempBuf, (char *) inet_ntoa(rtInfo->gateWay));
    else
        sprintf(tempBuf, "*.*.*.*\t");
    fprintf(stdout, "%s\t", tempBuf);

    /* Print Interface Name*/
    fprintf(stdout, "%s\t", rtInfo->ifName);

    /* Print Source address */
    if (rtInfo->srcAddr.s_addr != 0)
        strcpy(tempBuf, inet_ntoa(rtInfo->srcAddr));
    else
        sprintf(tempBuf, "*.*.*.*\t");
    fprintf(stdout, "%s\n", tempBuf);
}

void printGateway()
{
    printf("%s\n", gateway);
}
/* For parsing the route info returned */
void parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo)
{
    struct rtmsg *rtMsg;
    struct rtattr *rtAttr;
    int rtLen;

    rtMsg = (struct rtmsg *) NLMSG_DATA(nlHdr);

/* If the route is not for AF_INET or does not belong to main routing table
then return. */
    if ((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN))
        return;

/* get the rtattr field */
    rtAttr = (struct rtattr *) RTM_RTA(rtMsg);
    rtLen = RTM_PAYLOAD(nlHdr);
    for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen)) {
        switch (rtAttr->rta_type) {
        case RTA_OIF:
            if_indextoname(*(int *) RTA_DATA(rtAttr), rtInfo->ifName);
            break;
        case RTA_GATEWAY:
            rtInfo->gateWay.s_addr= *(u_int *) RTA_DATA(rtAttr);
            break;
        case RTA_PREFSRC:
            rtInfo->srcAddr.s_addr= *(u_int *) RTA_DATA(rtAttr);
            break;
        case RTA_DST:
            rtInfo->dstAddr .s_addr= *(u_int *) RTA_DATA(rtAttr);
            break;
        }
    }
    //printf("%s\n", inet_ntoa(rtInfo->dstAddr));

    if (rtInfo->dstAddr.s_addr == 0)
        sprintf(gateway, (char *) inet_ntoa(rtInfo->gateWay));
    //printRoute(rtInfo);

    return;
}


int main()
{
    struct nlmsghdr *nlMsg;
    struct rtmsg *rtMsg;
    struct route_info *rtInfo;
    char msgBuf[BUFSIZE];

    int sock, len, msgSeq = 0;

/* Create Socket */
    if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
        perror("Socket Creation: ");

    memset(msgBuf, 0, BUFSIZE);

/* point the header and the msg structure pointers into the buffer */
    nlMsg = (struct nlmsghdr *) msgBuf;
    rtMsg = (struct rtmsg *) NLMSG_DATA(nlMsg);

/* Fill in the nlmsg header*/
    nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));  // Length of message.
    nlMsg->nlmsg_type = RTM_GETROUTE;   // Get the routes from kernel routing table .

    nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;    // The message is a request for dump.
    nlMsg->nlmsg_seq = msgSeq++;    // Sequence of the message packet.
    nlMsg->nlmsg_pid = getpid();    // PID of process sending the request.

/* Send the request */
    if (send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0) {
        printf("Write To Socket Failed...\n");
        return -1;
    }

/* Read the response */
    if ((len = readNlSock(sock, msgBuf, msgSeq, getpid())) < 0) {
        printf("Read From Socket Failed...\n");
    return -1;
    }
/* Parse and print the response */
    rtInfo = (struct route_info *) malloc(sizeof(struct route_info));
//fprintf(stdout, "Destination\tGateway\tInterface\tSource\n");
    for (; NLMSG_OK(nlMsg, len); nlMsg = NLMSG_NEXT(nlMsg, len)) {
        memset(rtInfo, 0, sizeof(struct route_info));
        parseRoutes(nlMsg, rtInfo);
    }
    free(rtInfo);
    close(sock);

    printGateway();
    return 0;
}

离线

楼主 #3 2023-03-15 11:45:52

uuid
会员
注册时间: 2020-12-08
已发帖子: 45
积分: 31

Re: C 网络编程

How can I enumerate the list of network devices or interfaces in C or C++ in FreeBSD ?

I want a list like "ue0", "ath0", "wlan0".

I've been looking though the ifconfig(1) code but its not clear at all where the task is being performed.

I'll happily take an answer, a pointer to a man page, or a link to the appropriate line in ifconfig. I may have just missed it.

#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>
#include <arpa/inet.h>

int main(void)
{
    char          buf[1024];
    struct ifconf ifc;
    struct ifreq *ifr;
    int           sck;
    int           nInterfaces;
    int           i;

/* Get a socket handle. */
    sck = socket(AF_INET, SOCK_DGRAM, 0);
    if(sck < 0)
    {
        perror("socket");
        return 1;
    }

/* Query available interfaces. */
    ifc.ifc_len = sizeof(buf);
    ifc.ifc_buf = buf;
    if(ioctl(sck, SIOCGIFCONF, &ifc) < 0)
    {
        perror("ioctl(SIOCGIFCONF)");
        return 1;
    }

/* Iterate through the list of interfaces. */
    ifr         = ifc.ifc_req;
    nInterfaces = ifc.ifc_len / sizeof(struct ifreq);
    for(i = 0; i < nInterfaces; i++)
    {
        struct ifreq *item = &ifr[i];

    /* Show the device name and IP address */
        printf("%s: IP %s",
               item->ifr_name,
               inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr));


    /* Get the broadcast address (added by Eric) */
        if(ioctl(sck, SIOCGIFBRDADDR, item) >= 0)
            printf(", BROADCAST %s", inet_ntoa(((struct sockaddr_in *)&item->ifr_broadaddr)->sin_addr));
        printf("\n");
    }

        return 0;
}

https://stackoverflow.com/questions/23577787/how-can-i-enumerate-the-list-of-network-devices-or-interfaces-in-c-or-c-in-fre

$ ./i
lo: IP 127.0.0.1, BROADCAST 0.0.0.0
ens33: IP 192.168.80.178, BROADCAST 192.168.80.255
docker0: IP 172.17.0.1, BROADCAST 172.17.255.255

离线

楼主 #4 2023-03-15 21:43:36

uuid
会员
注册时间: 2020-12-08
已发帖子: 45
积分: 31

Re: C 网络编程

https://stackoverflow.com/questions/13140753/binding-with-wifi-interface-in-linux

binding with wifi interface in linux


if (getifaddrs(&ifaddrs) < 0) {
my_loge(CRIT, "address detection failed");
return(0);
}

// zero
count = 0;

// unset all but CAP_HOST and CAP_ROUTER
sysinfo->cap &= (CAP_HOST|CAP_ROUTER);
sysinfo->cap_active &= (CAP_HOST|CAP_ROUTER);
// reset counter
sysinfo->physif_count = 0;

// mark all interfaces
TAILQ_FOREACH(netif, netifs, entries) {
netif->type = NETIF_OLD;
}

for (ifaddr = ifaddrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {

// skip interfaces without addresses
if (ifaddr->ifa_addr == NULL) {
    my_log(INFO, "skipping interface %s", ifaddr->ifa_name);
    continue;
}

// only handle datalink addresses
if (ifaddr->ifa_addr->sa_family != NETIF_AF)
    continue;

// prepare ifr struct
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifaddr->ifa_name, sizeof(ifr.ifr_name));


// skip non-ethernet interfaces
memcpy(&saddrll, ifaddr->ifa_addr, sizeof(saddrll));
if (saddrll.sll_hatype != ARPHRD_ETHER) {
    my_log(INFO, "skipping interface %s", ifaddr->ifa_name);
    continue;
}
index = saddrll.sll_ifindex;
memcpy(&saddrdl, ifaddr->ifa_addr, sizeof(saddrdl));
if ((saddrdl.sdl_type != IFT_BRIDGE) &&
    (saddrdl.sdl_type != IFT_ETHER)) {
if (saddrdl.sdl_type != IFT_ETHER) {
    my_log(INFO, "skipping interface %s", ifaddr->ifa_name);
    continue;
}
index = saddrdl.sdl_index;

// check for interfaces that are down
enabled = 0;
if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0)
    enabled = (ifr.ifr_flags & IFF_UP);

// detect interface type
type = netif_type(sockfd, index, ifaddr, &ifr);

if (type == NETIF_REGULAR) { 
    my_log(INFO, "found ethernet interface %s", ifaddr->ifa_name);
    sysinfo->physif_count++;
} else if (type == NETIF_WIRELESS) {
    my_log(INFO, "found wireless interface %s", ifaddr->ifa_name);
    sysinfo->cap |= CAP_WLAN;
    sysinfo->cap_active |= (enabled == 1) ? CAP_WLAN : 0;
} else if (type == NETIF_TAP) {
    my_log(INFO, "found tun/tap interface %s", ifaddr->ifa_name);
} else if (type == NETIF_BONDING) {
    my_log(INFO, "found bond interface %s", ifaddr->ifa_name);
} else if (type == NETIF_BRIDGE) {
    my_log(INFO, "found bridge interface %s", ifaddr->ifa_name);
    sysinfo->cap |= CAP_BRIDGE; 
    sysinfo->cap_active |= (enabled == 1) ? CAP_BRIDGE : 0;
} else if (type == NETIF_VLAN) {
    my_log(INFO, "found vlan interface %s", ifaddr->ifa_name);
} else if (type == NETIF_INVALID) {
    my_log(INFO, "skipping interface %s", ifaddr->ifa_name);
    continue;
}

https://raw.githubusercontent.com/sspans/ladvd/master/src/netif.c

/*
 * $Id$
 *
 * Copyright (c) 2008, 2009, 2010
 *      Sten Spans <sten@blinkenlights.nl>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "common.h"
#include "util.h"
#include "proto/lldp.h"

#include <ifaddrs.h>
#include <dirent.h>
#include <ctype.h>

#if HAVE_ASM_TYPES_H
#include <asm/types.h>
#endif /* HAVE_ASM_TYPES_H */

#if HAVE_LINUX_SOCKIOS_H
#include <linux/sockios.h>
#endif /* HAVE_LINUX_SOCKIOS_H */

#if HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif /* HAVE_SYS_SOCKIO_H */

#ifdef HAVE_NETPACKET_PACKET_H
#include <netpacket/packet.h>
#endif /* HAVE_NETPACKET_PACKET_H */

#ifdef HAVE_NET_IF_DL_H
#include <net/if_dl.h>
#endif /* HAVE_NET_IF_DL_H */

#ifdef HAVE_NET_IF_TYPES_H
#include <net/if_types.h>
#endif /* HAVE_NET_IF_TYPES_H */


#ifdef AF_PACKET
#define NETIF_AF    AF_PACKET
#elif defined(AF_LINK)
#define NETIF_AF    AF_LINK
#endif

static int sockfd = -1;

static void netif_addrs(struct ifaddrs *, struct nhead *, struct my_sysinfo *);

#if defined(NETIF_LINUX)
#include "netif_linux.c"
#elif defined(NETIF_BSD)
#include "netif_bsd.c"
#endif

void netif_init() {
    if (sockfd == -1)
	sockfd = my_socket(AF_INET, SOCK_DGRAM, 0);
}

// create netifs for a list of interfaces
uint16_t netif_fetch(int ifc, char *ifl[], struct my_sysinfo *sysinfo,
		    struct nhead *netifs) {

    struct ifaddrs *ifaddrs, *ifaddr = NULL;
    struct ifreq ifr;
    int count = 0;
    int type, enabled;
    uint32_t index;
    struct parent_req mreq = {};

#ifdef AF_PACKET
    struct sockaddr_ll saddrll;
#elif defined(AF_LINK)
    struct sockaddr_dl saddrdl;
#endif

    // netifs
    struct netif *n_netif, *netif = NULL;

    if (sockfd == -1)
	my_fatal("please call netif_init first");

    if (getifaddrs(&ifaddrs) < 0) {
	my_loge(CRIT, "address detection failed");
	return(0);
    }

    // zero
    count = 0;

    // unset all but CAP_HOST and CAP_ROUTER
    sysinfo->cap &= (CAP_HOST|CAP_ROUTER);
    sysinfo->cap_active &= (CAP_HOST|CAP_ROUTER);
    // reset counter
    sysinfo->physif_count = 0;

    // mark all interfaces
    TAILQ_FOREACH(netif, netifs, entries) {
	netif->type = NETIF_OLD;
    }

    for (ifaddr = ifaddrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {

	// skip interfaces without addresses
	if (ifaddr->ifa_addr == NULL) {
	    my_log(INFO, "skipping interface %s", ifaddr->ifa_name);
	    continue;
	}

	// only handle datalink addresses
	if (ifaddr->ifa_addr->sa_family != NETIF_AF)
	    continue;

	// prepare ifr struct
	memset(&ifr, 0, sizeof(ifr));
	strlcpy(ifr.ifr_name, ifaddr->ifa_name, sizeof(ifr.ifr_name));


	// skip non-ethernet interfaces
#ifdef AF_PACKET
	memcpy(&saddrll, ifaddr->ifa_addr, sizeof(saddrll));
	if (saddrll.sll_hatype != ARPHRD_ETHER) {
	    my_log(INFO, "skipping interface %s", ifaddr->ifa_name);
	    continue;
	}
	index = saddrll.sll_ifindex;
#elif defined(AF_LINK)
	memcpy(&saddrdl, ifaddr->ifa_addr, sizeof(saddrdl));
#ifdef IFT_BRIDGE
	if ((saddrdl.sdl_type != IFT_BRIDGE) &&
	    (saddrdl.sdl_type != IFT_ETHER)) {
#else
	if (saddrdl.sdl_type != IFT_ETHER) {
#endif
	    my_log(INFO, "skipping interface %s", ifaddr->ifa_name);
	    continue;
	}
	index = saddrdl.sdl_index;
#endif

	// check for interfaces that are down
	enabled = 0;
	if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0)
	    enabled = (ifr.ifr_flags & IFF_UP);

	// detect interface type
	type = netif_type(sockfd, index, ifaddr, &ifr);

	if (type == NETIF_REGULAR) { 
	    my_log(INFO, "found ethernet interface %s", ifaddr->ifa_name);
	    sysinfo->physif_count++;
	} else if (type == NETIF_WIRELESS) {
	    my_log(INFO, "found wireless interface %s", ifaddr->ifa_name);
	    sysinfo->cap |= CAP_WLAN;
	    sysinfo->cap_active |= (enabled == 1) ? CAP_WLAN : 0;
	} else if (type == NETIF_TAP) {
	    my_log(INFO, "found tun/tap interface %s", ifaddr->ifa_name);
	} else if (type == NETIF_TEAMING) {
	    my_log(INFO, "found teaming interface %s", ifaddr->ifa_name);
	} else if (type == NETIF_BONDING) {
	    my_log(INFO, "found bond interface %s", ifaddr->ifa_name);
	} else if (type == NETIF_BRIDGE) {
	    my_log(INFO, "found bridge interface %s", ifaddr->ifa_name);
	    sysinfo->cap |= CAP_BRIDGE; 
	    sysinfo->cap_active |= (enabled == 1) ? CAP_BRIDGE : 0;
	} else if (type == NETIF_VLAN) {
	    my_log(INFO, "found vlan interface %s", ifaddr->ifa_name);
	} else if (type == NETIF_INVALID) {
	    my_log(INFO, "skipping interface %s", ifaddr->ifa_name);
	    continue;
	}


	// skip interfaces that are down
	if (enabled == 0) {
	    my_log(INFO, "skipping interface %s (down)", ifaddr->ifa_name);
	    continue;
	}


	my_log(INFO, "adding interface %s", ifaddr->ifa_name);

	// fetch / create netif
	if ((netif = netif_byindex(netifs, index)) == NULL) {
	    netif = my_malloc(sizeof(struct netif));
	    TAILQ_INSERT_TAIL(netifs, netif, entries);
	} else {
	    // reset everything up to the tailq_entry but keep protos
	    uint16_t protos = netif->protos;
	    memset(netif, 0, offsetof(struct netif, entries));
	    netif->protos = protos;
	}

        // copy name, index and type
	netif->index = index;
	strlcpy(netif->name, ifaddr->ifa_name, sizeof(netif->name));
	netif->type = type;

#ifdef HAVE_SYSFS
	mreq.op = PARENT_ALIAS;
	mreq.index = netif->index;

	if (my_mreq(&mreq))
	    strlcpy(netif->description, mreq.buf, IFDESCRSIZE);
#elif defined(SIOCGIFDESCR)
#ifndef __FreeBSD__
	ifr.ifr_data = (caddr_t)&netif->description;
#else
	ifr.ifr_buffer.buffer = &netif->description;
	ifr.ifr_buffer.length = IFDESCRSIZE;
#endif
	ioctl(sockfd, SIOCGIFDESCR, &ifr);
#endif

	if (sysinfo->mifname && (strcmp(netif->name, sysinfo->mifname) == 0))
	    sysinfo->mnetif = netif;

	// update counters
	count++;
    }

    // remove old interfaces
    TAILQ_FOREACH_SAFE(netif, netifs, entries, n_netif) {
	if (netif->type != NETIF_OLD)
	    continue;

	my_log(INFO, "removing old interface %s", netif->name);

	mreq.op = PARENT_CLOSE;
	mreq.index = netif->index;
	my_mreq(&mreq);

	TAILQ_REMOVE(netifs, netif, entries);
	if (sysinfo->mnetif == netif)
	    sysinfo->mnetif = NULL;
	free(netif);
    }

    // add child subif lists to each bond/bridge
    // detect vlan interface settings
    TAILQ_FOREACH(netif, netifs, entries) {
	my_log(INFO, "detecting %s settings", netif->name);
	switch(netif->type) {
#ifdef HAVE_LIBTEAM
	    case NETIF_TEAMING:
		netif_team(sockfd, netifs, netif, &ifr);
		break;
#endif /* HAVE_LIBTEAM */
	    case NETIF_BONDING:
		netif_bond(sockfd, netifs, netif, &ifr);
		break;
	    case NETIF_BRIDGE:
		netif_bridge(sockfd, netifs, netif, &ifr);
		break;
	    case NETIF_VLAN:
		netif_vlan(sockfd, netifs, netif, &ifr);
		break;
	    case NETIF_REGULAR:
		netif_device_id(sockfd, netif, &ifr);
		break;
	    default:
		break;
	}
    }

    // add addresses to netifs
    my_log(INFO, "fetching addresses for all interfaces");
    netif_addrs(ifaddrs, netifs, sysinfo);

    // use the first mac as chassis id
    if ((netif = TAILQ_FIRST(netifs)) != NULL)
	memcpy(&sysinfo->hwaddr, &netif->hwaddr, ETHER_ADDR_LEN);

    // validate detected interfaces
    if (ifc > 0) {
	count = 0;

	for (int j = 0; j < ifc; j++) {
	    netif = netif_byname(netifs, ifl[j]);
	    if (netif == NULL) {
		my_log(CRIT, "interface %s is invalid", ifl[j]);
	    } else if (netif->type == NETIF_VLAN) {
		my_log(CRIT, "vlan interface %s is not supported", ifl[j]);
	    } else {
		netif->argv = 1;
		count++;
	    }
	}
	if (count != ifc)
	    count = 0;

    } else if (count == 0) {
	my_log(CRIT, "no valid interface found");
    }

    if ((options & OPT_MNETIF) && !sysinfo->mnetif)
	my_log(CRIT, "could not detect the specified management interface");

    // cleanup
    freeifaddrs(ifaddrs);

    return(count);
};


// perform address detection for all netifs
static void netif_addrs(struct ifaddrs *ifaddrs, struct nhead *netifs,
		struct my_sysinfo *sysinfo) {
    struct ifaddrs *ifaddr;
    struct netif *netif, *mnetif;

    struct sockaddr_in saddr4;
    struct sockaddr_in6 saddr6;
#ifdef AF_PACKET
    struct sockaddr_ll saddrll;
#endif
#ifdef AF_LINK
    struct sockaddr_dl saddrdl;
#endif

    for (ifaddr = ifaddrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {

	// skip interfaces without addresses
	if (ifaddr->ifa_addr == NULL)
	    continue;

	// fetch the netif for this ifaddr
	netif = netif_byname(netifs, ifaddr->ifa_name);
	if (netif == NULL)
	    continue;

	if (ifaddr->ifa_addr->sa_family == AF_INET) {
	    if (netif->ipaddr4 != 0)
		continue;

	    // alignment
	    memcpy(&saddr4, ifaddr->ifa_addr, sizeof(saddr4));

	    memcpy(&netif->ipaddr4, &saddr4.sin_addr,
		  sizeof(saddr4.sin_addr));

	    // detect mnetif
	    if (sysinfo->mnetif || (sysinfo->maddr4 == 0))
		continue;

	    if (sysinfo->maddr4 == netif->ipaddr4)
		sysinfo->mnetif = netif;

	} else if (ifaddr->ifa_addr->sa_family == AF_INET6) {
	    if (!IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)netif->ipaddr6))
		continue;

	    // alignment
	    memcpy(&saddr6, ifaddr->ifa_addr, sizeof(saddr6));

	    // skip link-local
	    if (IN6_IS_ADDR_LINKLOCAL(&saddr6.sin6_addr))
		continue;

	    memcpy(&netif->ipaddr6, &saddr6.sin6_addr,
		  sizeof(saddr6.sin6_addr));

	    // detect mnetif
	    if (sysinfo->mnetif ||
		(IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)sysinfo->maddr6)))
		continue;

	    if (memcmp(&sysinfo->maddr6, &netif->ipaddr6,
			sizeof(sysinfo->maddr6)) == 0)
		sysinfo->mnetif = netif;
#ifdef AF_PACKET
	} else if (ifaddr->ifa_addr->sa_family == AF_PACKET) {

	    // alignment
	    memcpy(&saddrll, ifaddr->ifa_addr, sizeof(saddrll));

	    memcpy(&netif->hwaddr, &saddrll.sll_addr, ETHER_ADDR_LEN);
#endif
#ifdef AF_LINK
	} else if (ifaddr->ifa_addr->sa_family == AF_LINK) {

	    // alignment
	    memcpy(&saddrdl, ifaddr->ifa_addr, sizeof(saddrdl));

	    memcpy(&netif->hwaddr, LLADDR(&saddrdl), ETHER_ADDR_LEN);
#endif
	}
    }

    // return when no management netif is available
    if (!(options & OPT_MADDR) || !sysinfo->mnetif)
	return;
    mnetif = sysinfo->mnetif;

    // use management address when requested
    TAILQ_FOREACH(netif, netifs, entries) {
	netif->ipaddr4 = mnetif->ipaddr4;
	memcpy(&netif->ipaddr6, &mnetif->ipaddr6, sizeof(mnetif->ipaddr6));
    }
}


// perform media detection on physical interfaces
int netif_media(struct netif *netif) {

    struct ifreq ifr = {};

    if (sockfd == -1)
	my_fatal("please call netif_init first");

    netif->duplex = -1;
    netif->autoneg_supported = -1;
    netif->autoneg_enabled = -1;
    netif->autoneg_pmd = 0;
    netif->mau = 0;

    strlcpy(ifr.ifr_name, netif->name, sizeof(ifr.ifr_name));

    // interface mtu
    if (ioctl(sockfd, SIOCGIFMTU, (caddr_t)&ifr) >= 0)
	netif->mtu = ifr.ifr_mtu;
    else
	my_log(INFO, "mtu detection failed on interface %s", netif->name);

    // the rest only makes sense for real interfaces
    if (netif->type != NETIF_REGULAR)
	return(EXIT_SUCCESS);

    netif_physical(sockfd, netif);

    return(EXIT_SUCCESS);
}

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn