inet_XX族函数

在网络编程中, 经常会将网络字节转为本地字节或者将本地字节转为网络字节, 但是如果每次我们都是都通过htonl, ntohl函数需要将10进制转为整数, 甚至还用将字符串转为整数, 再转为网络字节, 或者反过来都是很麻烦的. 还好linux都是提供很方便的函数让两者之间进行转换.

转换函数

linux提供了多种函数满足我们任何转换的需求, 这都是inet_xxx族系列

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int inet_aton(const char *ip, struct in_addr *inp); // 本地转网络

char * inet_ntoa(struct in_addr inp);   // 网络转本地

in_addr_t inet_addr(const char *ip);    // 返回网络字节

in_addr_t inet_network(const char *ip); // 返回本地字节

接下来我们来在分析一下这几个函数

1. inet_aton函数

将点分十进制IP转化为网络字节序存放在inp中, 并返回该网络字节序对应的整数.

int inet_aton(const char *ip, struct in_addr *inp); 

失败 : 返回0.

成功 : 返回IP对应的网络字节序的数.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>

// 传入 127.0.0.1
int main(int argc, char *argv[])
{
    if(argc != 2)
        exit(-1);

    struct in_addr addr;
    if(inet_aton(argv[1], &addr) == 0)
        exit(-1);
    printf("0x%08x\n", addr.s_addr); // 0x0100007f
 
    exit(EXIT_SUCCESS);
}
2. inet_ntoa函数

将一个32位网络字节序的二进制IP地址转换成相应的点分十进制的IP地址.

char *inet_ntoa(struct in_addr inp);

失败 : 返回NULL.

成功 : 返回字符串指针.

注意 : 该函数不是线程安全函数, 不可重入. 因为不同线程调用会覆盖掉其他线程的缓冲区.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char *argv[])
{
    struct in_addr net_addr;
    net_addr.s_addr = 0x0100007f;   // 127.0.0.1
    char *host_addr;

    host_addr = inet_ntoa(net_addr);
    printf("%s\n", host_addr);  // 127.0.0.1
 
    exit(EXIT_SUCCESS);
}
3. inet_addr函数

将一个点分十进制转换网络字节序IP.

in_addr_t inet_addr(const char *ip);

失败 : 返回INADDR_NONE. 部分手册上返回的是-1, 这个问题与inet_network一样了.

成功 : 返回网络字节IP.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

// 输入 127.0.0.1
int main(int argc, char *argv[])
{
    in_addr_t addr;

    addr = inet_addr(argv[1]);
    printf("0x%08x\n", addr);   // 0x0100007f

    exit(EXIT_SUCCESS);
}
4. inet_network函数

将点分十进制IP转化为主机字节序

in_addr_t inet_network(const char *ip);

失败 : 返回-1.

成功 : 返回主机对应的数.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// 输入 127.0.0.1
int main(int argc, char *argv[])
{
    in_addr_t addr;

    addr = inet_network(argv[1]);
    printf("0x%08x\n", addr);   // 0x7f000001
 
    exit(EXIT_SUCCESS);
}

该函数在某些情况下并不正确, 如果IP地址是255.255.255.255返回的则是0xffffffff, 转为十进制就是-1. 分不清出-1表示的是错误的返回值还是IP地址. 可以使用inet_pton()inet_ntop()函数来代替, 这里就不详细的分析了, 有兴趣的可以自己查一下.

总结

本节分析了4个函数, 重点需要掌握的是inet_aton函数.

  • 4个函数使用, 以及返回值
  • inet_network返回值的问题
  • inet_ntoa并不是线程安全的函数

转载于:https://www.cnblogs.com/0xfffffff0/p/10362127.html

LOCAL STATUS get_wan_status(DS_HANDLE_CONTEXT *context, JSON_OBJPTR section_obj) { LINK_STATUS link_status = {0}; DEVICE_BASIC_INFO basic_info = {0}; U32 up_time = 0; char ip[STR_IP_LEN] = {0}; char mac_str[STR_MAC_LEN] = {0}; if (NULL == section_obj) { return SLP_ESYSTEM; } if (0 == ds_read(LINK_STATUS_PATH, (U8 *)&link_status, sizeof(link_status))) { NIFC_DEBUG("Read link status config fail."); return SLP_ESYSTEM; } if (NULL == inet_ntop(AF_INET, (void *)&(link_status.ipaddr), ip, STR_IP_LEN)) { return ERROR; } jso_add_string(section_obj, "ipaddr", ip); if (NULL == inet_ntop(AF_INET, (void *)&(link_status.netmask), ip, STR_IP_LEN)) { return ERROR; } jso_add_string(section_obj, "netmask", ip); if (NULL == inet_ntop(AF_INET, (void *)&(link_status.gateway), ip, STR_IP_LEN)) { return ERROR; } jso_add_string(section_obj, "gateway", ip); if (NULL == inet_ntop(AF_INET, (void *)&(link_status.pri_dns), ip, STR_IP_LEN)) { return ERROR; } jso_add_string(section_obj, "pri_dns", ip); if (NULL == inet_ntop(AF_INET, (void *)&(link_status.snd_dns), ip, STR_IP_LEN)) { return ERROR; } jso_add_string(section_obj, "snd_dns", ip); jso_add_int(section_obj, "phy_status", link_status.phy_status); switch (link_status.proto) { case PROTO_DHCP: jso_add_string(section_obj, "proto", "dhcp"); break; case PROTO_STATIC: jso_add_string(section_obj, "proto", "static"); break; default: return SLP_EINVARG; } if (LINK_UP == link_status.link_status) { up_time = time(NULL) - g_link_params.link_up_time; } jso_add_int(section_obj, "error_code", link_status.error_code); jso_add_int(section_obj, "link_status", link_status.link_status); jso_add_int(section_obj, "internet_status", link_status.internet_status); jso_add_int(section_obj, "up_time", up_time); jso_add_int(section_obj, "up_speed", link_status.up_speed); jso_add_int(section_obj, "down_speed", link_status.down_speed); jso_add_int(section_obj, "pppoe_link_status", link_status.pppoe_link_status); if (NULL == inet_ntop(AF_INET, (void *)&(link_status.pppoe_ipv4), ip, STR_IP_LEN)) { return ERROR; } jso_add_string(section_obj, "pppoe_ipv4", ip); if (0 != ds_read(DEVICE_BASIC_INFO_PATH, (U8 *)&basic_info, sizeof(DEVICE_BASIC_INFO))) { snprintf(mac_str, sizeof(mac_str), "%02x-%02x-%02x-%02x-%02x-%02x", (unsigned char)basic_info.mac[0], (unsigned char)basic_info.mac[1], (unsigned char)basic_info.mac[2], (unsigned char)basic_info.mac[3], (unsigned char)basic_info.mac[4], (unsigned char)basic_info.mac[5]); jso_add_string(section_obj, "mac", mac_str); } return OK; }
最新发布
09-20
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <net/if.h> #include <sys/ioctl.h> #include <arpa/inet.h> #include <pthread.h> #include <time.h> #include <stdint.h> #include <stddef.h> // 包含offsetof宏 #include <linux/if_packet.h> // 包含sockaddr_ll定义 #include <net/ethernet.h> // 包含以太网相关定义 #include <sys/types.h> #include <netinet/if_ether.h> // 包含ARP协议定义 // 定义常量 #define MAC_LENGTH 6 #define IPV4_LENGTH 4 #define ETH_HEADER_SIZE 14 #define ARP_PACKET_SIZE 42 #define INITIAL_ENTRIES 128 // 链表节点结构 struct list_head { struct list_head *next; struct list_head *prev; }; // ARP节点结构 typedef struct _ARP_NODE { struct list_head head; // 链表节点 unsigned char mac[MAC_LENGTH]; // MAC地址 uint32_t ip; // IP地址(网络字节序) time_t t_tm; // 扫描时间 time_t expire_time; // 过期时间 } ARP_NODE; // 程序配置结构 typedef struct { uint32_t enable_scan; // 功能开关(0/1) uint32_t scan_cycle; // 扫描周期(秒) uint32_t packet_interval; // 发包间隔(毫秒) uint32_t entry_ttl; // 条目有效期(秒) uint32_t start_ip; // 起始IP(网络字节序) uint32_t end_ip; // 结束IP(网络字节序) } ARP_CONFIG; // ARP头结构 typedef struct ARP_HEADER { uint16_t ar_hrd; /* 硬件类型(1表示以太网) */ uint16_t ar_pro; /* 协议类型(0x0800表示IPv4) */ uint8_t ar_hln; /* MAC地址长度(6) */ uint8_t ar_pln; /* IP地址长度(4) */ uint16_t ar_op; /* 操作码(1=请求,2=响应) */ uint8_t ar_sha[MAC_LENGTH]; /* 发送方MAC地址 */ uint8_t ar_sip[IPV4_LENGTH]; /* 发送方IP地址 */ uint8_t ar_tha[MAC_LENGTH]; /* 目标MAC地址 */ uint8_t ar_tip[IPV4_LENGTH]; /* 目标IP地址 */ } ARP_HEADER; // 全局变量 struct list_head arp_result_head; // 扫描结果链表头 ARP_CONFIG arp_config_origin; // 全局配置 pthread_mutex_t lock; // 线程锁 // 链表操作宏 #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) // 初始化链表 void init_list_head(struct list_head *list) { list->next = list; list->prev = list; } // 添加节点到链表头部 void list_add(struct list_head *new_node, struct list_head *head) { new_node->next = head->next; new_node->prev = head; head->next->prev = new_node; head->next = new_node; } // 从链表中删除节点 void list_del(struct list_head *entry) { entry->next->prev = entry->prev; entry->prev->next = entry->next; entry->next = NULL; entry->prev = NULL; } // 获取节点结构体指针 #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr) - offsetof(type, member))) // 获取网络接口索引 unsigned int if_nametoindex(const char *ifname) { struct ifreq ifr; int sockfd; sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket"); return 0; } memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0) { close(sockfd); perror("ioctl"); return 0; } close(sockfd); return ifr.ifr_ifindex; // 使用系统定义的ifr_index } // 获取本地MAC地址 void get_local_mac(const char *ifname, uint8_t *mac) { struct ifreq ifr; int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (sock < 0) { perror("socket"); exit(EXIT_FAILURE); } strncpy(ifr.ifr_name, ifname, IFNAMSIZ); if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) { perror("ioctl"); close(sock); exit(EXIT_FAILURE); } memcpy(mac, ifr.ifr_hwaddr.sa_data, MAC_LENGTH); close(sock); } // 获取本地IP地址 void get_local_ip(const char *ifname, struct in_addr *local_ip) { struct ifreq ifr; int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (sock < 0) { perror("socket"); exit(EXIT_FAILURE); } strncpy(ifr.ifr_name, ifname, IFNAMSIZ); if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) { perror("ioctl"); close(sock); exit(EXIT_FAILURE); } struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; local_ip->s_addr = sin->sin_addr.s_addr; close(sock); } // 创建原始套接字 int create_arp_socket() { int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP)); if (sock < 0) { perror("socket"); exit(EXIT_FAILURE); } return sock; } // 构建ARP请求报文 void build_arp_packet(const char *ifname, struct ARP_HEADER *arp, uint32_t target_ip) { arp->ar_hrd = htons(ARPHRD_ETHER); arp->ar_pro = htons(ETH_P_IP); // ETH_P_IP 定义在 netinet/if_ether.h arp->ar_hln = MAC_LENGTH; arp->ar_pln = IPV4_LENGTH; arp->ar_op = htons(ARPOP_REQUEST); // 设置源MAC(本机MAC) get_local_mac(ifname, arp->ar_sha); // 设置源IP(本机IP) struct in_addr local_ip; get_local_ip(ifname, &local_ip); memcpy(arp->ar_sip, &local_ip.s_addr, IPV4_LENGTH); // 设置目标MAC(广播) memset(arp->ar_tha, 0x00, MAC_LENGTH); // 设置目标IP memcpy(arp->ar_tip, &target_ip, IPV4_LENGTH); } // 发送ARP请求 void send_arp(int sock, const char *ifname, struct ARP_HEADER *arp) { // 构建完整的以太网帧 uint8_t packet[ARP_PACKET_SIZE]; // 以太网目标地址(广播) memset(packet, 0xFF, 6); // 以太网源地址(本机MAC) get_local_mac(ifname, packet + 6); // 以太网类型(ARP) packet[12] = 0x08; // ETH_P_ARP高位 packet[13] = 0x06; // ETH_P_ARP低位 // ARP包内容 memcpy(packet + ETH_HEADER_SIZE, arp, sizeof(*arp)); // 发送到网络接口 struct sockaddr_ll dest; memset(&dest, 0, sizeof(dest)); dest.sll_family = AF_PACKET; dest.sll_protocol = htons(ETH_P_ARP); dest.sll_ifindex = if_nametoindex(ifname); dest.sll_halen = ETH_ALEN; memset(dest.sll_addr, 0xFF, ETH_ALEN); // 广播地址 if (sendto(sock, packet, ARP_PACKET_SIZE, 0, (struct sockaddr *)&dest, sizeof(dest)) < 0) { perror("sendto"); } } // 接收ARP响应 int recv_arp(int sock, struct ARP_HEADER *arp_resp) { uint8_t buffer[ETH_HEADER_SIZE + sizeof(struct ARP_HEADER)]; ssize_t len = recv(sock, buffer, sizeof(buffer), 0); if (len < ETH_HEADER_SIZE) { return -1; // 接收失败 } // 检查是否为ARP包 if (buffer[12] != 0x08 || buffer[13] != 0x06) { return -1; // 非ARP包 } // 解析ARP包 struct ARP_HEADER *arp = (struct ARP_HEADER *)(buffer + ETH_HEADER_SIZE); // 检查是否为ARP响应 if (ntohs(arp->ar_op) != ARPOP_REPLY) { return -1; // 非ARP响应 } memcpy(arp_resp, arp, sizeof(struct ARP_HEADER)); return len; } // 查找或创建ARP节点 ARP_NODE* find_or_create_node(uint32_t ip) { struct list_head *pos; ARP_NODE *node; // 遍历链表查找节点 list_for_each(pos, &arp_result_head) { node = list_entry(pos, ARP_NODE, head); if (node->ip == ip) { return node; } } // 创建新节点 node = (ARP_NODE*)malloc(sizeof(ARP_NODE)); if (!node) { perror("malloc"); return NULL; } // 初始化节点 memset(node->mac, 0, MAC_LENGTH); node->ip = ip; node->t_tm = time(NULL); node->expire_time = node->t_tm + arp_config_origin.entry_ttl; // 添加到链表头部 list_add(&node->head, &arp_result_head); return node; } // ARP扫描线程 void* scan_thread(void *arg) { const char *ifname = (const char*)arg; int sock = create_arp_socket(); while (arp_config_origin.enable_scan) { // 打印当前扫描范围 char start_ip_str[INET_ADDRSTRLEN]; char end_ip_str[INET_ADDRSTRLEN]; struct in_addr start_ip = {.s_addr = arp_config_origin.start_ip}; struct in_addr end_ip = {.s_addr = arp_config_origin.end_ip}; inet_ntop(AF_INET, &start_ip, start_ip_str, sizeof(start_ip_str)); inet_ntop(AF_INET, &end_ip, end_ip_str, sizeof(end_ip_str)); printf("[SCAN] Scanning from %s to %s\n", start_ip_str, end_ip_str); // 转换为主机字节序 uint32_t host_start_ip = ntohl(arp_config_origin.start_ip); uint32_t host_end_ip = ntohl(arp_config_origin.end_ip); // 遍历IP范围 for (uint32_t host_ip = host_start_ip; host_ip <= host_end_ip; host_ip++) { uint32_t net_ip = htonl(host_ip); char ip_str[INET_ADDRSTRLEN]; struct in_addr ip_addr = {.s_addr = net_ip}; inet_ntop(AF_INET, &ip_addr, ip_str, sizeof(ip_str)); printf("[SCAN] Sending ARP to %s\n", ip_str); struct ARP_HEADER arp_req; build_arp_packet(ifname, &arp_req, net_ip); // 发送ARP请求 send_arp(sock, ifname, &arp_req); // 按间隔等待 usleep(arp_config_origin.packet_interval * 1000); } // 等待扫描周期 sleep(arp_config_origin.scan_cycle); } close(sock); return NULL; } // ARP响应处理 void process_arp_response(struct ARP_HEADER *arp) { uint32_t ip; memcpy(&ip, arp->ar_sip, IPV4_LENGTH); time_t now = time(NULL); pthread_mutex_lock(&lock); // 查找或创建节点 ARP_NODE *node = find_or_create_node(ip); if (node) { memcpy(node->mac, arp->ar_sha, MAC_LENGTH); node->t_tm = now; node->expire_time = now + arp_config_origin.entry_ttl; } pthread_mutex_unlock(&lock); } // 超时清理线程 void* cleanup_thread(void *arg) { while (1) { sleep(5); // 每5秒检查一次 pthread_mutex_lock(&lock); time_t now = time(NULL); struct list_head *pos, *next; list_for_each_safe(pos, next, &arp_result_head) { ARP_NODE *node = list_entry(pos, ARP_NODE, head); if (node->expire_time < now) { // 移除超时节点 char ip_str[INET_ADDRSTRLEN]; struct in_addr ip_addr = {.s_addr = node->ip}; inet_ntop(AF_INET, &ip_addr, ip_str, sizeof(ip_str)); printf("[CLEAN] Removing expired node: %s\n", ip_str); list_del(&node->head); free(node); } } pthread_mutex_unlock(&lock); } return NULL; } // 打印ARP表 void print_arp_table() { pthread_mutex_lock(&lock); printf("\nARP Table:\n"); printf("--------------------------------------------------\n"); printf("IP Address\t\tMAC Address\t\tLast Update\n"); struct list_head *pos; list_for_each(pos, &arp_result_head) { ARP_NODE *node = list_entry(pos, ARP_NODE, head); // 打印IP地址 char ip_str[INET_ADDRSTRLEN]; struct in_addr ip_addr = {.s_addr = node->ip}; inet_ntop(AF_INET, &ip_addr, ip_str, sizeof(ip_str)); printf("%s\t\t", ip_str); // 打印MAC地址 printf("%02X:%02X:%02X:%02X:%02X:%02X\t\t", node->mac[0], node->mac[1], node->mac[2], node->mac[3], node->mac[4], node->mac[5]); // 打印最后更新时间 char time_str[30]; struct tm *tm_info = localtime(&node->t_tm); strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info); printf("%s\n", time_str); } printf("--------------------------------------------------\n"); pthread_mutex_unlock(&lock); } // 更新配置 void update_config(ARP_CONFIG new_config) { pthread_mutex_lock(&lock); // 验证IP范围有效性 if (ntohl(new_config.end_ip) < ntohl(new_config.start_ip)) { fprintf(stderr, "Invalid IP range\n"); } else { arp_config_origin = new_config; } pthread_mutex_unlock(&lock); } int main() { const char *interface = "eth0"; // 网络接口名,根据系统调整 // 初始化全局变量 init_list_head(&arp_result_head); pthread_mutex_init(&lock, NULL); // 设置默认配置 arp_config_origin.enable_scan = 1; arp_config_origin.scan_cycle = 300; // 5分钟 arp_config_origin.packet_interval = 100; // 100毫秒 arp_config_origin.entry_ttl = 1800; // 30分钟 arp_config_origin.start_ip = inet_addr("192.168.114.1"); arp_config_origin.end_ip = inet_addr("192.168.114.254"); // 启动扫描线程 pthread_t scan_tid, cleanup_tid; if (pthread_create(&scan_tid, NULL, scan_thread, (void*)interface) != 0) { perror("pthread_create"); exit(EXIT_FAILURE); } if (pthread_create(&cleanup_tid, NULL, cleanup_thread, NULL) != 0) { perror("pthread_create"); exit(EXIT_FAILURE); } // 启动ARP响应接收 int arp_sock = create_arp_socket(); // 主循环 while (1) { struct ARP_HEADER arp_resp; if (recv_arp(arp_sock, &arp_resp) > 0) { process_arp_response(&arp_resp); } // 每隔30秒打印一次ARP表 static time_t last_print = 0; time_t now = time(NULL); if (now - last_print >= 30) { print_arp_table(); last_print = now; } } // 清理资源(理论上不会执行到这里) pthread_join(scan_tid, NULL); pthread_join(cleanup_tid, NULL); close(arp_sock); pthread_mutex_destroy(&lock); return 0; } 运行后终端显示: [SCAN] Scanning from 192.168.114.1 to 192.168.114.254 [SCAN] Sending ARP to 192.168.114.1 ioctl: No such device
08-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值