ubuntu18-recvfrom接收不到广播报文异常分析

目录

前言

一、UDP广播接收程序

二、异常原因分析

总结


前言

        在ubuntu18.04系统中,编写udp接收程序发现接收不到广播报文,使用抓包工具tcpdump可以抓取到广播报文,在此对该现象分析解析如下文所示。

一、UDP广播接收程序

        UDP广播接收程序如下所示,广播发送程序使用上位机向255.255.255.255地址11100端口发送广播报文。

int CreateUdpSocket(int iUdpPort)
{
    int flag = 1;
    int err;
    int iSockFd = 0;
    short sPort = (short)iUdpPort;
    struct sockaddr_in tSockAddr;
    
	
    iSockFd = socket(AF_INET, SOCK_DGRAM, 0);
    if (iSockFd <= 0)
    {
        printf("[%s]Create local socket Error.\n", __FUNCTION__);
        return -1;
    }

    tSockAddr.sin_family      = AF_INET;
    tSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    tSockAddr.sin_port        = htons(sPort);
	
    err = setsockopt(iSockFd, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(int));
    if(err != 0)
    {
        printf("ERR: setsockopt  socket error. err = %d,errno = %d[%s] port %d\n",err, errno, strerror(errno), iUdpPort);
        close(iSockFd);
        return -2;
    }
    if (bind(iSockFd, (struct sockaddr*)&tSockAddr, sizeof(struct sockaddr_in)) < 0)
    {
        printf("ERR:  bind error.\n");
        close(iSockFd);
        return -3;
    }
    
    return iSockFd;
}

void *StartBroadCastThread(void *arg)
{
    char acInterface[] = "eth0";
    int ifindex = 0;
    int iSocket = -1;
    int iLen = 10000;
    int iRet = 0;
    int iBroadcastIface = -1;
    int iEthIndex = 0;
    int iEthNum = 0;
    int i;
    unsigned char *pcData = NULL;
    struct sockaddr_in tSockAddr;
    int iSockAddrLen = sizeof(tSockAddr);
    int iRecvLen = 0;
    short sSendLen = 0;
    PT_MSG_INFO ptMsg = NULL;
    T_MSG_BROADCAST_DEV_INFO *ptBroadCastInfo = NULL;
    //T_ETHNAME_INFO atEthNameInfo[MAX_ETH_NUM];
 //   T_DEV_NET_INFO *ptNetInfo = NULL;
    char acBroadcastIface[24];
    char acTmpBuf[512];
    int iSessionId = 0;
    T_ETHNAME_INFO atEthNameInfo[4];
    
    iSocket = CreateUdpSocket(MSG_TEST_BROADCAST_PORT);
    if (iSocket < 0)
    {
        printf("socket udp failed\n");
        return NULL;
    }
    
    pcData = (char *)malloc(iLen);
    if (NULL == pcData)
    {
        printf("[%s] malloc failed\n", __FUNCTION__);
        close(iSocket);
        return NULL;
    }
    
    //ptHead = (PT_MSG_HEAD)pcBuf;
    while (1)
    {
        iRecvLen = recvfrom(iSocket, pcData, iLen, 0, 
                                   (struct sockaddr *)&tSockAddr, (socklen_t*)&iSockAddrLen);
        if(iRecvLen <= 0)
        {
            printf("[%s] recvfrom fail, .\n", __FUNCTION__);
            close(iSocket);
            free(pcData);
            return NULL;
        }
        if (iRecvLen < 4)
        {
            printf("iRecvLen = %d\n", iRecvLen);
            continue;
        }
        printf("[%s]recv len %d, magic %d, cmd %d\n", __FUNCTION__, iRecvLen, pcData[0], pcData[1]);
        if ((pcData[0] == MSG_MAGIC_FLAG) && (pcData[1] == MSG_CLI2SERV_BROADCAST_QUERY))
        {
        	  printf("[%s]%d\n", __FUNCTION__, __LINE__);
        	  memset(pcData, 0, iLen);
            ptMsg = (PT_MSG_INFO)pcData;
            ptBroadCastInfo = (T_MSG_BROADCAST_DEV_INFO *)ptMsg->acMsgData;
           /* srand((int)time(0));
            iSessionId = (int)(300000.0*rand()/(RAND_MAX+1.0));
            memset(ptBroadCastInfo, 0, sizeof(T_MSG_BROADCAST_DEV_INFO));
            
            ptBroadCastInfo->iSessionId = htonl(iSessionId);*/
            

            iRet =  ABI_GetDevInfo((char *)ptBroadCastInfo, sizeof(T_MSG_BROADCAST_DEV_INFO));
            
            iRet = COMM_GetNetWorkCardNum(&iEthNum, atEthNameInfo);
            if (iRet < 0)
            {
                printf("Get None NetWork Card\n");
                continue;
            }

            for (i = 0; i < iEthNum; i++)
            {
                sSendLen = sizeof(T_MSG_BROADCAST_DEV_INFO);
                ptMsg->tMsgHead.magic = MSG_MAGIC_FLAG;
                ptMsg->tMsgHead.cmd = MSG_SERV2CLI_BROADCAST_QUERY_RESP;
                ptMsg->tMsgHead.sLen = htons(sSendLen);
                COMM_GetIpAddr(atEthNameInfo[i].acName, ptBroadCastInfo->acIpAddr, sizeof(ptBroadCastInfo->acIpAddr));
                read_interface(atEthNameInfo[i].acName, &ifindex, NULL, NULL);
                send_broadcast(ifindex, MSG_TEST_BROADCAST_PORT, ntohs(tSockAddr.sin_port), pcData, sizeof(T_MSG_HEAD) + sSendLen);
            }   
        }
    }
    
    close(iSocket);
    if (pcData)
    {
        free(pcData);
        pcData = NULL;
    }
    
    return NULL;
}

使用tcpdump抓包工具可以抓到广播报文:

但是通过recvfrom函数则接收不到该报文。

二、异常原因分析

        考虑到ubuntu可以自带防火墙,但是通过查询ubuntu系统的防火墙功能,发现并没有开启,通过查询相关资料,发现可能跟Linux内核网络参数的设置有关,涉及到反向路径过滤,在/etc/sysctl.conf中有反向路径过滤参数可以设置,两项参数如下所示:

# Uncomment the next two lines to enable Spoof protection (reverse-path filter)
# Turn on Source Address Verification in all interfaces to
# prevent some spoofing attacks
#net.ipv4.conf.default.rp_filter=0
#net.ipv4.conf.all.rp_filter=0

两项参数解释如下:

  1. net.ipv4.conf.default.rp_filter=0: 这个设置表示在默认的网络接口上关闭反向路径过滤。反向路径过滤用于验证从系统收到的数据包是否通过与内核期望的相同的网络接口返回。将其设置为0表示禁用反向路径过滤。

  2. net.ipv4.conf.all.rp_filter=0: 这个设置表示在所有网络接口上关闭反向路径过滤。与前一个设置不同,这个设置应用于系统上的所有网络接口。

        由于上位机软件发送该广播报文时并没有绑定源地址,且此时ubuntu系统是默认开启源地址验证,则该报文则被系统方向过滤掉了。鉴于该种情况,在ubuntu系统中关闭反向路径过滤即可,如下:

重启ubuntu系统,在此运行程序时发现recvform可以接收到该广播报文。


总结

        在ubuntu系统如果碰到recvform接收不到广播报文的情况,可以参考本文内容解决。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flypig哗啦啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值