自定义协议创建的C语言Socket绑定失败问题求助
AF_PACKET原始Socket调用bind失败问题排查
我用自定义协议RCP创建了AF_PACKET类型的Raw Socket,其他参数配置(比如sockaddr_ll的协议、硬件类型、接口索引等)都正常,但调用bind时出错。编译命令为gcc rcping.c -o rcping -lcap,相关代码如下:
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <net/if_arp.h> #include <net/if.h> #include <asm/types.h> #include <linux/if_ether.h> #include <libcap.h> #include <string.h> #define RCP 49152 #define ARPHRD_ETHER 1 #define PACKET_RX 2 #define sizepkt 512 typedef unsigned short ushort_t; struct sockaddr_ll { ushort_t sll_family; /* address family (AF_LINK) */ ushort_t sll_protocol; /* link-layer protocol (e.g., Ethernet) */ int32_t sll_ifindex; /* interface index */ uint16_t sll_hatype; /* ARP hardware type */ uint8_t sll_pkttype; /* packet type */ uint8_t sll_halen; /* hardware address length */ uint8_t sll_addr[8]; /* hardware address (e.g., MAC address) */ }; uint16_t srcport; uint16_t extport; uint16_t srcport1; uint16_t extport2; char payload[256]; int main(int argc, char* argv[]) { int intextport = atoi(argv[1]); cap_t caps = cap_init(); cap_value_t *capvl = 0; cap_set_flag(caps, CAP_NET_RAW, 1, capvl, CAP_SET); int sockfd = socket(AF_PACKET, SOCK_RAW, RCP); if (sockfd < 0) { printf("Socket not created\n"); printf("%d\n", sockfd); return -1; } else { printf("Socket Created successfully\n"); } printf("test1\n"); struct sockaddr_in *dst_addr = malloc((size_t)sizeof(struct sockaddr_in)); printf("1\n"); char buffer[sizepkt]; printf("hi\n"); dst_addr->sin_family = AF_INET; printf("test2\n"); dst_addr->sin_port = htons(intextport); printf("test3\n"); inet_pton(AF_INET, "127.0.0.1", &dst_addr->sin_addr); printf("test4\n"); struct sockaddr_ll *src_addr = malloc((size_t)sizeof(struct sockaddr_ll)); int error1 = src_addr->sll_family = AF_PACKET; if (error1 < 0) { printf("socket family couldn't be set\n"); printf("%d\n", error1); return -1; } int error2 = src_addr->sll_protocol = RCP; if (error2 < 0) { printf("The Internet protocol(IP) couldn't be set up\n"); printf("%d\n", error2); return -1; } printf("test5\n"); int error3 = src_addr->sll_ifindex = if_nametoindex("wlan0"); if (error3 < 0) { printf("local interface couldn't be set up\n"); printf("%d\n", error3); return -1; } int error4 = src_addr->sll_pkttype = PACKET_RX; if (error4 < 0) { printf("package type couldn't be set\n"); printf("%d\n", error4); return -1; } int error5 = src_addr->sll_halen = 6; if (error5 < 0) { printf("package type couldn't be set\n"); printf("%d\n", error5); return -1; } int error6 = src_addr->sll_hatype = ARPHRD_ETHER; if (error6 < 0) { printf("package type couldn't be set\n"); printf("%d\n", error6); return -1; } printf("test6\n"); struct sockaddr *addr = (struct sockaddr *)&dst_addr; printf("1\n"); struct sockaddr *interlcal = (struct sockaddr *)&src_addr; strcpy(payload, "This packet was sent using RCPing under the Really Crappy Protocol"); extport = htons(intextport); srcport = htons(RCP); char chrsrcport[16]; char chrextport[16]; sprintf(chrsrcport, "%d", srcport); sprintf(chrextport, "%d", extport); memcpy(buffer, chrsrcport, sizeof(chrsrcport)); printf("7\n"); memcpy(buffer + sizeof(chrsrcport), chrextport, sizeof(chrextport)); printf("8\n"); memcpy(buffer + sizeof(chrsrcport) + sizeof(chrextport), payload, 8); printf("9\n"); srcport1 = htons(RCP); extport2 = htons(intextport); int miku = bind(sockfd, interlcal, sizeof(interlcal)); printf("10\n"); if (miku < 0) { printf("client interface couldn't be set up\n"); printf("%d\n", miku); return -1; } int jumanji = connect(sockfd, addr, sizeof(addr)); if (jumanji < 0) { printf("Couldn't establish a connection using RCP, unsurprisingly\n"); printf("%d", jumanji); return -1; } else { while (main) { ssize_t senresult = send(sockfd, buffer, sizeof(buffer), 0); if (senresult < 0) { printf("Package wasn't sent"); } } } }
关键错误修正
bind参数错误
你错误地将指针的地址(&src_addr)强转为sockaddr*,并且传入的长度是指针的大小(sizeof(interlcal)),而非sockaddr_ll结构体的实际大小。修正后代码:struct sockaddr *interlcal = (struct sockaddr *)src_addr; int miku = bind(sockfd, interlcal, sizeof(struct sockaddr_ll));sockaddr_ll地址族错误
AF_PACKET类型Socket对应的地址族必须是AF_LINK,不是AF_PACKET,修改:src_addr->sll_family = AF_LINK;权限未生效
初始化cap后未将权限应用到进程,且原代码中capvl设为0会导致权限设置失败,修正后:cap_t caps = cap_init(); cap_value_t capvl = CAP_NET_RAW; cap_set_flag(caps, CAP_EFFECTIVE, 1, &capvl, CAP_SET); cap_set_proc(caps); cap_free(caps);AF_PACKET不支持connect
AF_PACKET是链路层原始Socket,不存在TCP/UDP的连接概念,需删除connect调用,发送数据时需自行构造以太网帧头部。移除重复结构体定义
系统头文件<linux/if_packet.h>已经定义了sockaddr_ll,自行定义可能导致内存布局不一致,删除自定义的struct sockaddr_ll,添加头文件包含:#include <linux/if_packet.h>循环与send长度错误
while(main)是无效循环,改为while(1);send时应传入实际要发送的字节数,而非整个buffer大小:size_t send_len = sizeof(chrsrcport) + sizeof(chrextport) + 8; ssize_t senresult = send(sockfd, buffer, send_len, 0);
内容的提问来源于stack exchange,提问作者The QNX girl
相关产品推荐
相关产品推荐

