使用 socket() 你不能选择你的网络设备。这是通过 sendto () 和 recvfrom () 完成的。在 recvfrom () 和 sendto () 的参数 5 中,您放置了一个 sockaddr 结构。那里有一个 sockaddr.sll_ifindex 字段,您可以在其中选择网卡。在我的环境中,enp3s0 为 3,enp3s1 为 4。
查看电缆模拟器代码。我测试了 20 分钟,它没有问题。
// network cable emulator
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
signed long long llmac (unsigned char* pmac)
{
signed long long sum= 0;
signed long long sumd;
for (signed long lauf= 0; lauf < 6; lauf++)
{
sumd= pmac[lauf];
sum= sum | (sumd << (40 - lauf*8));
}
return sum;
}
struct macliste
{
signed long long anz;
signed long long mac[100000];
macliste ();
void add (unsigned char* pmac);
signed long neu (unsigned char* pmac);
};
macliste::macliste ()
{
anz= 0;
}
void macliste::add (unsigned char* pmac)
{
if (neu (pmac))
{
mac[anz]= llmac (pmac);
anz++;
}
}
signed long macliste::neu (unsigned char* pmac)
{
signed long long smac;
smac= llmac (pmac);
for (signed long lauf= 0; lauf < anz; lauf++)
if (mac[lauf] == smac)
return 0;
return 1;
}
int main ()
{
int sockemp, socksenleft, socksenright;
signed long result;
unsigned char transferpuffer[10000];
struct sockaddr_ll sockaddrleft;
struct sockaddr_ll sockaddrright;
struct sockaddr_ll sockaddrboth;
signed long sockaddrsize= sizeof (sockaddrboth);
char ifnameleft[IFNAMSIZ] = "enp3s0";
char ifnameright[IFNAMSIZ] = "enp3s1";
struct ifreq ifindexleft;
struct ifreq ifindexright;
int indexleft;
int indexright;
// Socket öffnen
sockemp= socket (AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
printf ("sockemp: %5d\n", sockemp);
// Socket öffnen
socksenleft= socket (AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
printf ("socksenleft: %5d\n", socksenleft);
// Socket öffnen
socksenright= socket (AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
printf ("socksenright: %5d\n", socksenright);
printf ("\n");
/* den Index des Interfaces ermitteln */
printf ("Interfacename left: %s\n", ifnameleft);
printf ("Interfacename right: %s\n", ifnameright);
printf ("\n");
memset (&ifindexleft, 0, sizeof (struct ifreq));
memset (&ifindexright, 0, sizeof (struct ifreq));
strncpy (ifindexleft.ifr_name, ifnameleft, IFNAMSIZ);
strncpy (ifindexright.ifr_name, ifnameright, IFNAMSIZ);
result= ioctl (socksenleft, SIOCGIFINDEX, &ifindexleft);
result= ioctl (socksenright, SIOCGIFINDEX, &ifindexright);
indexleft= ifindexleft.ifr_ifindex;
indexright= ifindexright.ifr_ifindex;
printf ("interfaceresult: %5ld indexleft %5d\n", result, indexleft);
printf ("interfaceresult: %5ld indexright %5d\n", result, indexright);
printf ("\n");
/* Socketadresse vorbereiten */
memset (&sockaddrleft, 0, sizeof(struct sockaddr_ll));
sockaddrleft.sll_family = PF_PACKET; /* RAW communication */
sockaddrleft.sll_hatype = ARPHRD_ETHER; /* Ethernet */
sockaddrleft.sll_pkttype = PACKET_OTHERHOST; /* Ziel ist ein anderer Rechner */
sockaddrleft.sll_ifindex = indexleft; /* Interface-Index */
sockaddrleft.sll_halen = ETH_ALEN; /* Address length*/
/* Socketadresse vorbereiten */
memset (&sockaddrright, 0, sizeof(struct sockaddr_ll));
sockaddrright.sll_family = PF_PACKET; /* RAW communication */
sockaddrright.sll_hatype = ARPHRD_ETHER; /* Ethernet */
sockaddrright.sll_pkttype = PACKET_OTHERHOST; /* Ziel ist ein anderer Rechner */
sockaddrright.sll_ifindex = indexright; /* Interface-Index */
sockaddrright.sll_halen = ETH_ALEN; /* Address length*/
/* Socketadresse vorbereiten */
memset (&sockaddrboth, 0, sizeof(struct sockaddr_ll));
sockaddrboth.sll_family = PF_PACKET; /* RAW communication */
sockaddrboth.sll_hatype = ARPHRD_ETHER; /* Ethernet */
sockaddrboth.sll_pkttype = PACKET_OTHERHOST; /* Ziel ist ein anderer Rechner */
sockaddrboth.sll_halen = ETH_ALEN; /* Address length*/
// Schnittstellen in den Promiskuitätsmodus schalten
struct ifreq ifr;
int raw_socket;
char deviceleft[100]= "enp3s0";
char deviceright[100]= "enp3s1";
memset (&ifr, 0, sizeof (struct ifreq));
// Open A Raw Socket Deviceleft
if ((raw_socket = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
{
printf ("ERROR: Could not open socket, Got #?\n");
exit (1);
}
/* Set the device to use */
strcpy (ifr.ifr_name, deviceleft);
/* Get the current flags that the device might have */
if (ioctl (raw_socket, SIOCGIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not retrive the flags from the device.\n");
exit (1);
}
/* Set the old flags plus the IFF_PROMISC flag */
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl (raw_socket, SIOCSIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not set flag IFF_PROMISC");
exit (1);
}
printf ("Entering promiscuous mode\n");
/* Configure the device */
if (ioctl (raw_socket, SIOCGIFINDEX, &ifr) < 0)
{
perror ("Error: Error getting the device index.\n");
exit (1);
}
// Open A Raw Socket Deviceright
if ((raw_socket = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
{
printf ("ERROR: Could not open socket, Got #?\n");
exit (1);
}
/* Set the device to use */
strcpy (ifr.ifr_name, deviceright);
/* Get the current flags that the device might have */
if (ioctl (raw_socket, SIOCGIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not retrive the flags from the device.\n");
exit (1);
}
/* Set the old flags plus the IFF_PROMISC flag */
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl (raw_socket, SIOCSIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not set flag IFF_PROMISC");
exit (1);
}
printf ("Entering promiscuous mode\n");
/* Configure the device */
if (ioctl (raw_socket, SIOCGIFINDEX, &ifr) < 0)
{
perror ("Error: Error getting the device index.\n");
exit (1);
}
// Pakete transferieren
getchar ();
signed long packetcounter= 0;
macliste emplisteleft;
macliste emplisteright;
while (1)
{
result= recvfrom (sockemp, transferpuffer, 10000, 0, (struct sockaddr*) (&sockaddrboth), (socklen_t*)&sockaddrsize);
if ((sockaddrboth.sll_ifindex != indexleft) && (sockaddrboth.sll_ifindex != indexright))
continue;
packetcounter++;
if ((sockaddrboth.sll_ifindex == indexleft) && (emplisteright.neu (transferpuffer + 6)))
{
emplisteleft.add (transferpuffer + 6); // Ethernet II Paket Quelladresse
result= sendto (socksenright, transferpuffer, result, 0, (struct sockaddr*) &sockaddrright, sizeof (struct sockaddr_ll));
printf ("sendresult: %5ld %2d\n", result, indexright);
}
if ((sockaddrboth.sll_ifindex == indexright) && (emplisteleft.neu (transferpuffer + 6)))
{
emplisteright.add (transferpuffer + 6); // Ethernet II Paket Quelladresse
result= sendto (socksenleft, transferpuffer, result, 0, (struct sockaddr*) &sockaddrleft, sizeof (struct sockaddr_ll));
printf ("sendresult: %5ld %2d\n", result, indexleft);
}
printf ("Packet %10ld empresult: %5ld %2d %20llx %10lld %10lld\n", packetcounter, result, sockaddrboth.sll_ifindex, llmac (transferpuffer + 6), emplisteleft.anz, emplisteright.anz);
}
return 0;
}
在 ubuntu 20.04 服务器下使用 gcc 9.3.0 编译:
g++ transferraw.cc -std=c++17 -Wall -Wextra -Wconversion -pedantic-errors -O2 -o transferraw