【问题标题】:C programming -> wpa_supplicant connected -> udp broadcast sendto "Network Unreachable"C 编程 -> wpa_supplicant 已连接 -> udp 广播发送到“网络不可达”
【发布时间】: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 &gt; 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


【解决方案1】:

我认为您确实想在这里使用原始套接字。虽然这是真的(根据@cklin),这意味着您必须重新发明轮子,但 dhcp 是不寻常的,因为您在正确配置接口之前发送数据包。作为一个简单的指南,我建议您查看busybox 以及它的dhclient 脚本是如何工作的。另一种选择是libpcap。这会捕获回复(即使是不直接发给您的回复),并且还有一个鲜为人知的功能,即能够发送原始数据包。我已经成功用它写了一个dhcp服务器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-26
    • 2015-07-31
    • 1970-01-01
    • 2021-07-30
    • 2015-03-14
    • 1970-01-01
    • 2018-03-25
    • 2013-09-16
    相关资源
    最近更新 更多