背景
https://www.jianshu.com/p/a3692e86cb1e
总结
通过路由表来达到在指定网卡上发包的效果。
解决方案
- 更改路由表
使用python的pysnmp库更方便
这里给出的是windows自带的dos命令
route change 255.255.255.255 mask 255.255.255.255 192.168.1.101 metric 230 if 22
其中 192.168.1.101 是你本机的IP地址
metric 230 是你决定的metric值,比其他的小就行
if 22 是无线网络接口编号,也是通过route print命令看出来的
- 得到无线网卡信息之后,在特定网络广播(192.168.1.255)而不使用255.255.255.255
main.c
#include<stdio.h>
#include<WinSock2.h>
#include "GetNICMsg.h"
void raise_message(char *msg);
char * changeIPaddrtoBroadcastIPaddr(char *ipaddr, char *netmask);
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
#define RECV_PORT 2019
#define SEND_PORT 2019
#define MAXBUFLEN 1024
#define DONTPRINTIT 0
#define PRINTIT 1
#define FIRST_USING_WIRELESS_NIC 0
int main()
{
WSADATA wsa;
WSAStartup(0x201, &wsa);
SOCKET sock_host;
sock_host = socket(AF_INET, SOCK_DGRAM, 0);
BOOL bBoardcast = TRUE;
if (SOCKET_ERROR == setsockopt(sock_host, SOL_SOCKET, SO_BROADCAST, (char*)&bBoardcast, sizeof(bBoardcast)))
{
printf("setsockopt failed with error code: %d/n", WSAGetLastError());
return -1;
}
char *ipaddr = NULL, *netmask = NULL,*ip_broadcast;
if (getAllAdapterInfo(&ipaddr, &netmask, MIB_IF_TYPE_WiFi, DONTPRINTIT, FIRST_USING_WIRELESS_NIC)!= 0)
{
raise_message("找不到一个可用的无线网卡\n");
closesocket(sock_host);
return -1;
}
// 获得无线网卡的广播地址
ip_broadcast = changeIPaddrtoBroadcastIPaddr(ipaddr, netmask);
sockaddr_in addr_local, addr_remote;
addr_remote.sin_addr.S_un.S_addr = inet_addr(ip_broadcast);
addr_remote.sin_port = htons(SEND_PORT);
addr_remote.sin_family = AF_INET;
int retval, headlen = sizeof(addr_remote);
char buf[MAXBUFLEN] = "hello???";
int ID_list_temp[5] = { htons(1), htons(2), htons(4), htons(8), htons(16) };
while (1)
{
for (int i = 0; i < 5; ++i)
{
retval = sendto(sock_host, (char *)(ID_list_temp + i), sizeof(int), 0, (sockaddr *)&addr_remote, headlen);
if (retval < 0)
{
retval = WSAGetLastError();
return -1;
}
}
}
return 0;
}
void raise_message(char *msg)
{
printf(msg);
}
char * changeIPaddrtoBroadcastIPaddr(char *ipaddr,char *netmask)
{
unsigned long int ipaddr_int = inet_addr(ipaddr);
unsigned long int netmask_int = inet_addr(netmask);
unsigned long int netmask_low = inet_addr("255.255.255.255");
netmask_low = netmask_low^netmask_int;
ipaddr_int = ipaddr_int | netmask_low;
char *ipbroadcast;
in_addr ipaddr_in;
ipaddr_in.S_un.S_addr = ipaddr_int;
ipbroadcast = inet_ntoa(ipaddr_in);
return ipbroadcast;
}
GetNICMsg.cpp
#include "GetNICMsg.h"
void GetMsgfromcur(char** ipaddr, char **netmask,PIP_ADAPTER_INFO cur, bool printit)
{
IP_ADDR_STRING *pIpAddrString = &(cur->IpAddressList);
if (printit)
{
cout << "IP:" << pIpAddrString->IpAddress.String << endl;
cout << "子网掩码:" << pIpAddrString->IpMask.String << endl;
cout << "Context:" << pIpAddrString->Context << endl;
char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
// mac 地址一般6个字节
// mac 二进制转16进制字符串
char macStr[18] = { 0 };//12+5+1
int k = 0;
for (int j = 0; j < cur->AddressLength; j++){
macStr[k++] = hex[(cur->Address[j] & 0xf0) >> 4];
macStr[k++] = hex[cur->Address[j] & 0x0f];
macStr[k++] = '-';
}
macStr[k - 1] = 0;
cout << "MAC:" << macStr << endl; // mac地址 16进制字符串表示
cout << "--------------------------------------------------" << endl;
}
*ipaddr = (char *)malloc(sizeof(IP_ADDRESS_STRING));
strcpy(*ipaddr, pIpAddrString->IpAddress.String);
*netmask = (char *)malloc(sizeof(IP_ADDRESS_STRING));
strcpy(*netmask, pIpAddrString->IpMask.String);
}
int getAllAdapterInfo(char** ipaddr, char **netmask, int NICtype, bool printit, int sequence)
{
if (sequence == 0)
sequence = 1;
int CurrentSequence = 1;
//char *ipaddr = (char *)malloc(sizeof(IP_ADDRESS_STRING));
PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO[ADAPTERNUM];// 20个网卡空间 足够了
unsigned long stSize = sizeof(IP_ADAPTER_INFO) * ADAPTERNUM;
// 获取所有网卡信息,参数二为输入输出参数
int nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);
// 空间不足
if (ERROR_BUFFER_OVERFLOW == nRel) {
// 释放空间
if (pIpAdapterInfo != NULL)
delete[] pIpAdapterInfo;
return -1;
}
PIP_ADAPTER_INFO cur = pIpAdapterInfo;
// 多个网卡 通过链表形式链接起来的
while (cur){
if (cur->Type == NICtype)
{
switch (cur->Type) {
case MIB_IF_TYPE_OTHER:
break;
case MIB_IF_TYPE_ETHERNET:
GetMsgfromcur(ipaddr, netmask,cur, printit);
if (strcmp(UeslessIPaddr, *ipaddr) != 0)
{
if (CurrentSequence == sequence)
return 0;
else
++CurrentSequence;
}
break;
case MIB_IF_TYPE_TOKENRING:
break;
case MIB_IF_TYPE_FDDI:
break;
case MIB_IF_TYPE_PPP:
break;
case MIB_IF_TYPE_LOOPBACK:
break;
case MIB_IF_TYPE_SLIP:
break;
case MIB_IF_TYPE_WiFi:
GetMsgfromcur(ipaddr, netmask, cur, printit);
if (strcmp(UeslessIPaddr, *ipaddr) != 0)
{
if (CurrentSequence == sequence)
return 0;
else
++CurrentSequence;
}
break;
default://无线网卡,Unknown type
break;
}
}
cur = cur->Next;
}
// 释放空间
if (pIpAdapterInfo != NULL)
delete[] pIpAdapterInfo;
}
void getAllAdapterInfo()
{
PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO[ADAPTERNUM];// 20个网卡空间 足够了
unsigned long stSize = sizeof(IP_ADAPTER_INFO) * ADAPTERNUM;
// 获取所有网卡信息,参数二为输入输出参数
int nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);
// 空间不足
if (ERROR_BUFFER_OVERFLOW == nRel) {
// 释放空间
if (pIpAdapterInfo != NULL)
delete[] pIpAdapterInfo;
return;
}
PIP_ADAPTER_INFO cur = pIpAdapterInfo;
// 多个网卡 通过链表形式链接起来的
while (cur){
cout << "网卡描述:" << cur->Description << endl;
switch (cur->Type) {
case MIB_IF_TYPE_OTHER:
break;
case MIB_IF_TYPE_ETHERNET:
{
IP_ADDR_STRING *pIpAddrString = &(cur->IpAddressList);
cout << "IP:" << pIpAddrString->IpAddress.String << endl;
cout << "子网掩码:" << pIpAddrString->IpMask.String << endl;
cout << "Context:" << pIpAddrString->Context << endl;
}
break;
case MIB_IF_TYPE_TOKENRING:
break;
case MIB_IF_TYPE_FDDI:
break;
case MIB_IF_TYPE_PPP:
break;
case MIB_IF_TYPE_LOOPBACK:
break;
case MIB_IF_TYPE_SLIP:
break;
default://无线网卡,Unknown type
{
IP_ADDR_STRING *pIpAddrString = &(cur->IpAddressList);
cout << "IP:" << pIpAddrString->IpAddress.String << endl;
cout << "子网掩码:" << pIpAddrString->IpMask.String << endl;
}
break;
}
char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
// mac 地址一般6个字节
// mac 二进制转16进制字符串
char macStr[18] = { 0 };//12+5+1
int k = 0;
for (int j = 0; j < cur->AddressLength; j++){
macStr[k++] = hex[(cur->Address[j] & 0xf0) >> 4];
macStr[k++] = hex[cur->Address[j] & 0x0f];
macStr[k++] = '-';
}
macStr[k - 1] = 0;
cout << "MAC:" << macStr << endl; // mac地址 16进制字符串表示
cur = cur->Next;
cout << "--------------------------------------------------" << endl;
}
// 释放空间
if (pIpAdapterInfo != NULL)
delete[] pIpAdapterInfo;
}
GetNICMsg.h
#ifndef __GETNICMSG__
#define __GETNICMSG__
#include <iostream>
#include <vector>
#include <WinSock2.h>
#include <Iphlpapi.h>
#pragma comment(lib,"Iphlpapi.lib")
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
using namespace std;
#define ADAPTERNUM 20
#define MIB_IF_TYPE_WiFi 71
#define UeslessIPaddr "0.0.0.0"
int getAllAdapterInfo(char** ipaddr, char **netmask, int NICtype, bool printit, int sequence);
void getAllAdapterInfo();
void GetMsgfromcur(char** ipaddr, char **netmask, PIP_ADAPTER_INFO cur, bool printit);
#endif
- 通过setsockopt函数确定在哪个网卡上发送
在windows下不可行,但是在Linux下可以通过setsockopt(..., SOL_SOCKET, SO_BINDTODEVICE, "ethX")
完成。
参考https://stackoverflow.com/questions/683624/udp-broadcast-on-all-interfaces