【发布时间】:2013-12-02 09:17:30
【问题描述】:
我在发送广播包以检测 dhcp 服务器(255.255.255.255 到端口 67)上被困了几个星期。
如果有人能花时间发现我在思考过程中的缺陷,我将不胜感激。
第 1 步:准备我的系统以自己构建 dhcp 客户端
我制作了 shellscript 来杀死 dhcpd 并断开我的 Wifi 并使用 wpa_supplicant 再次连接
echo "Killing DHCP daemon to open up port 68"
sudo killall -TERM dhcpcd dhclient
echo "Stopping Network Service"
sudo /etc/init.d/network stop
echo "Ifdown on network interfaces"
sudo /sbin/ifconfig eth0 down
sudo /sbin/ifconfig wlan0 down
echo "Connecting to Wifi using WPA_Supplicant"
sudo /usr/sbin/wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant/wpa_supplicant.conf &
第 2 步:检查无线连接是否正常
user@suse:sudo /usr/sbin/wpa_cli status
root's password:
Selected interface 'wlan0'
bssid=5c:35:3b:64:79:59
ssid=Joehoe
id=0
mode=station
pairwise_cipher=TKIP
group_cipher=TKIP
key_mgmt=WPA2-PSK
wpa_state=COMPLETED
address=00:26:c7:1e:a2:42
第 3 步:遇到我的问题
旁注:如果此时运行 /usr/sbin/dhclient 工作正常,那么我得出的结论是无线真的很好
我运行以下代码:
/** Compile : gcc -m32 dhcpclient.c -o dhcpclient */
#define DHCPSERVERPORT 67
#define DHCPCLIENTPORT 68
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/******************************************************************/
/************ DHCP Message Structure ********************/
typedef struct {
unsigned char op; // Message opcode/type // unsigned char can be replaced by uint8_t, see C manual for info
unsigned char htype; // Hardware addr type
unsigned char hlen; // Hardware addr length
unsigned char hops; // Number of relay agent hops from client
unsigned long xid; // Transaction ID
unsigned short secs; // Seconds since client started looking
unsigned short flags; // Flag bits
struct in_addr ciaddr; // Client IP address (if already in use)
struct in_addr yiaddr; // Client IP address
struct in_addr siaddr; // IP address of next server to talk to
struct in_addr giaddr; // DHCP relay agent IP address
unsigned char chaddr[16]; // Client hardware address
char sname[64]; // Server name
char file[128]; // Boot filename
char magiccookie[4]; // DHCP option cookie
char options[59]; // Optional parameters (actual length dependent on MTU).
} dhcp_msg;
/************ DHCP DISCOVER ********************/
dhcp_msg dhcpdiscover(){
//struct dhcp_msg dhcpdiscover;
dhcp_msg dhcpdiscover;
dhcpdiscover.op = 1;
dhcpdiscover.htype = 1;
dhcpdiscover.hlen = 6;
dhcpdiscover.hops = 0;
dhcpdiscover.xid = 0;
dhcpdiscover.secs = 0;
dhcpdiscover.flags = 0;
dhcpdiscover.ciaddr.s_addr = htonl(INADDR_ANY);
dhcpdiscover.yiaddr.s_addr = htonl(INADDR_ANY);
dhcpdiscover.siaddr.s_addr = htonl(INADDR_ANY);
dhcpdiscover.giaddr.s_addr = htonl(INADDR_ANY);
dhcpdiscover.chaddr[0] = 0x00;
dhcpdiscover.chaddr[1] = 0x26;
dhcpdiscover.chaddr[2] = 0xC7;
dhcpdiscover.chaddr[3] = 0x1E;
dhcpdiscover.chaddr[4] = 0xA2;
dhcpdiscover.chaddr[5] = 0x42;
dhcpdiscover.chaddr[6] = 0x00;
dhcpdiscover.chaddr[7] = 0x00;
dhcpdiscover.chaddr[8] = 0x00;
dhcpdiscover.chaddr[9] = 0x00;
dhcpdiscover.chaddr[10] = 0x00;
dhcpdiscover.chaddr[11] = 0x00;
dhcpdiscover.chaddr[12] = 0x00;
dhcpdiscover.chaddr[13] = 0x00;
dhcpdiscover.chaddr[14] = 0x00;
dhcpdiscover.chaddr[15] = 0x00;
memset(dhcpdiscover.sname,0,sizeof(dhcpdiscover.sname));
memset(dhcpdiscover.file,0,sizeof(dhcpdiscover.file));
/************ setting magiccookie and options to 0 -> recognized as BootP protocol ***/
dhcpdiscover.magiccookie[0] = 99;
dhcpdiscover.magiccookie[1] = 130;
dhcpdiscover.magiccookie[2] = 83;
dhcpdiscover.magiccookie[3] = 99;
dhcpdiscover.options[0] = 53;
dhcpdiscover.options[1] = 1;
dhcpdiscover.options[2] = 1;
dhcpdiscover.options[3] = 255;
/** always set 0xff as DHCP End option to close option listing, rest is padding **/
return dhcpdiscover;
}
void printDHCPStructure(dhcp_msg dhcpstructure){
dhcp_msg dhcpstruct = dhcpstructure;
printf("\n\tDHCP Field\tBytes\tValue\n");
printf("\t----------------------------------\n");
printf("\top : \t\t1\t%x\n", dhcpstruct.op);
printf("\thtype : \t1\t%x\n", dhcpstruct.htype);
printf("\thlen : \t\t1\t%x\n", dhcpstruct.hlen);
printf("\thops : \t\t1\t%x\n", dhcpstruct.hops);
printf("\txid : \t\t1\t%x\n", dhcpstruct.xid);
printf("\tsecs : \t\t1\t%x\n", dhcpstruct.secs);
printf("\tflags : \t1\t%x\n", dhcpstruct.flags);
printf("\tciaddr : \t1\t%s\n", dhcpstruct.ciaddr);
printf("\tyiaddr : \t1\t%s\n", dhcpstruct.yiaddr);
printf("\tsiaddr : \t1\t%s\n", dhcpstruct.siaddr);
printf("\tgiaddr : \t1\t%s\n", dhcpstruct.giaddr);
printf("\tchadddr[MAC] : \t16\t%x:%x:%x:%x:%x:%x\n", dhcpstruct.chaddr[0],dhcpstruct.chaddr[1],dhcpstruct.chaddr[2],dhcpstruct.chaddr[3],dhcpstruct.chaddr[4],dhcpstruct.chaddr[5]);
printf("\tsname : \t64\t%s\n", dhcpstruct.sname);
printf("\tfile : \t\t128\t%s\n", dhcpstruct.file);
printf("\tmgckie_0 : \t1\t%d\n", (unsigned char)dhcpstruct.magiccookie[0]);
printf("\tmgckie_1 : \t1\t%d\n", (unsigned char)dhcpstruct.magiccookie[1]);
printf("\tmgckie_2 : \t1\t%d\n", (unsigned char)dhcpstruct.magiccookie[2]);
printf("\tmgckie_3 : \t1\t%d\n", (unsigned char)dhcpstruct.magiccookie[3]);
printf("\toptions : \t59\t\n");
printf("\n");
}
int bindBroadcastUdpv4(int socket,short int socketport)
{
int clientsock = socket;
struct sockaddr_in udpaddr;
memset((char *)&udpaddr, 0, sizeof(udpaddr));
udpaddr.sin_family = AF_INET;
udpaddr.sin_addr.s_addr = htonl(INADDR_ANY);
udpaddr.sin_port = htons(socketport);
if (bind(clientsock, (struct sockaddr *)&udpaddr, sizeof(udpaddr)) < 0)
{
printf("Binding the UDP Socket failed\n");
printf("Tip 1 : Run 'sudo netstat -l -u -n -p | grep %d'\n", socketport);
printf("Tip 2 : Run program with root privileges\n");
perror("Error");
exit(1);
}
else
{
return 1;
}
}
/******************************************************************/
/******************************************************************/
int main(int argc, char *argv[])
{
/** Creating UDP client socket **/
int clientsock = socket(AF_INET, SOCK_DGRAM, 0);
int broadcastpermissions = 1;
short int clientport = DHCPCLIENTPORT;
short int destinationport = DHCPSERVERPORT;
if (clientsock < 0)
{
perror("Error @ Step 1 : Cannot create client socket");
}
else
{
printf("Step 1 : Client socket created succesfully\n");
}
/** Give client socket broadcast permissions **/
if (broadcastpermissions)
{
int ret = setsockopt(clientsock,SOL_SOCKET,SO_REUSEADDR,&broadcastpermissions,sizeof(broadcastpermissions));
if (ret != 0)
{
printf("Error @ step 1BisA : Giving Client Socket reuse options FAILED: %d\n", ret);
exit(0);
}
ret = setsockopt(clientsock,SOL_SOCKET,SO_BROADCAST,&broadcastpermissions,sizeof(broadcastpermissions));
if (ret != 0)
{
printf("Error @ step 1BisB : Giving Client Socket broadcast permissions FAILED: %d\n", ret);
exit(0);
}
else
{
printf("\tSetting broadcast permissions on client socket succeeded\n");
}
}
/** Binding the client socket **/
if (bindBroadcastUdpv4(clientsock, clientport))
{
printf("Step 2 : Socket is binded succesfully\n");
}
/** Create DHCP Discovery data structure **/
dhcp_msg dhcpdiscovery = dhcpdiscover();
printf("Step 3 : DHCP Discovery Data Structure created\n");
printDHCPStructure(dhcpdiscovery);
/** Trying to broadcast to 255.255.255.255 on port 67 to detect DHCP Servers */
struct sockaddr_in destinationaddr;
memset((char *)&destinationaddr, 0, sizeof(destinationaddr));
destinationaddr.sin_family = AF_INET;
//destinationaddr.sin_addr.s_addr = INADDR_BROADCAST;
destinationaddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
destinationaddr.sin_port = htons(destinationport);
//destinationaddr.sin_port = destinationport;
/** translate Hexadecimal notation of IP Address to decimal **/
int IP1 = (ntohl(destinationaddr.sin_addr.s_addr) >> 24) & 0xFF;
int IP2 = (ntohl(destinationaddr.sin_addr.s_addr) >> 16) & 0xFF;
int IP3 = (ntohl(destinationaddr.sin_addr.s_addr) >> 8) & 0xFF;
int IP4 = (ntohl(destinationaddr.sin_addr.s_addr)) & 0xFF;
//while(1){};
printf("DEBUG : Clientsock = %d\n", clientsock);
printf("DEBUG : .sin_addr = %p\n", destinationaddr.sin_addr.s_addr);
printf("DEBUG : .sin_port = %d\n", destinationaddr.sin_port);
printf("DEBUG : .sin_port = %d\n", destinationport);
/******************************************************************************************************************************************************************/
int a = sendto(clientsock,&dhcpdiscovery,sizeof(dhcpdiscovery),0,(struct sockaddr *)&destinationaddr, sizeof(destinationaddr));
if (a < 0)
{
printf("A is :\%d\n", a);
printf("UDP Message to %d.%d.%d.%d on port %d failed\n",IP1,IP2,IP3,IP4,destinationport);
perror("Sending failed : ");
return 667;
}
else
{
printf("UDP Messsage to %d.%d.%d.%d on port %d SUCCESS !\n",IP1,IP2,IP3,IP4,destinationport);
}
close(clientsock);
}
/******************************************************************/
/******************************************************************/
额外信息: A) 如前所述,在运行 dhclient 时,我得到分配的 IP 地址,wireshark 向我显示 dhcp 对话
B) 在已经分配了ipaddress的情况下运行我自己的代码时,发送成功
C) sendTo 返回的错误是 'Network Unreachable'
所以我的问题是:我已连接到我的无线 AP,我需要额外执行哪一步才能让我的套接字发送广播数据包? 这样做的原因是学习网络和学习编程,所以我的编程技能并不出色,这就是为什么你可能会看到荒谬的代码。我很欣赏它上面的任何 cmets,但更愿意坚持我的主要问题。
向地球同胞致以最诚挚的问候!
【问题讨论】:
-
您是否以 root 身份运行您的代码?发送到广播地址通常需要 Root 权限。
-
嗨,cklin,一个非常好的人“Saravana”向我暗示了答案。要使常规套接字起作用,您需要接口上的 IP 地址。 AFAIK,本机 dhclient 将使用原始套接字。所以,是的,我的代码以 root 身份执行,但我使用的是常规套接字。我现在正在验证如何使用原始套接字进行操作。如果这是答案,为了清楚起见,我将在这里回答我自己的问题。但是,如果原始套接字不是解决方案。我会深入挖掘!
-
我刚刚编译了你的代码,它在我的机器上运行良好。 tcpdump 显示正确的输出:
10.191.17.134.68 > 255.255.255.255.67: [udp sum ok] BOOTP/DHCP, Request from 00:00:00:00:00:00, length 312, xid 0xff7f0000, Flags [none] (0x0000) Client-Ethernet-Address 00:00:00:00:00:00 -
无论如何,您都不应该使用原始套接字。 DHCP 使用 UDP 作为其传输。使用原始套接字仅意味着您必须通过手动编码自己的 UDP 标头来重新发明轮子。
-
我同意,当我已经分配了 IP 地址(在 wlan0 或 eth0 上)时,代码运行良好。问题是当您发送 DHCP 发现时,您没有在该特定点上分配 IP 地址(因为您正在请求一个)。所以,只有在这种情况下,我才会得到“网络无法访问”。这就是为什么有人让我找到我需要使用原始套接字进行广播的答案,即使没有分配 IP 地址(用于 DHCP 发现)。
标签: c sockets networking