我正在玩 STP 数据包并编写程序原始套接字来修改它们。从 eth0 读取发送到 eth1。系统是 ubuntu 14.10/ Kernel 3.something。使用 Karat 的其他计算机生成数据包,Wireshark 也在运行此接口。注入一个数据包,第一次运行 recvfrom 后没有停止。从 eth0 读取相同的数据包并将其发送到 eth1。调试会话??????? 最终版本应该从 eth0 读取所有帧,转发所有并将所有 STP 放入“单播隧道”中 - 读取所有 eth1 帧和转发 eth0 并“解包”特殊的“隧道”帧。
我在这里放了一些代码:
typedef struct {
unsigned char mac[6];
unsigned char ifName[IFNAMSIZ];
int sockfd;
struct sockaddr_ll socketaddress;
struct ifreq ifopts; /* set promiscuous mode */
} interfaces;
extern int errno;
nt i;
int sockopt;
ssize_t numbytes;
unsigned char InBuf[BUF_SIZ]; // this is the frame buffer
interfaces in,out; // interface struct var's
unsigned char PeerMac[6]; // Peer mac for simple Tunnel
unsigned char myMac[6]; // my Peer address
int c;
unsigned char IEEE802_1q_STP[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0d};
/* Header structures */
struct ether_header *InTunnelPtr = (struct ether_header*) InBuf;
struct ether_header *InPtr = (struct ether_header*) (InBuf+14);
/ First Do it for IN_IF
memset(&in.socketaddress, 0, sizeof(struct sockaddr_ll)); // clear Var
in.socketaddress.sll_family = PF_PACKET;
in.socketaddress.sll_protocol = htons(ETH_P_ALL); // just dummy, don't needed
in.socketaddress.sll_halen = ETH_ALEN;
/* Open PF_PACKET socket, listening for EtherType ETHER_TYPE */
if ((in.sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("listener: socket");
return -1;
}
memset (&in.ifopts, 0, sizeof (struct ifreq));
// Set interface to promiscuous mode - do we need to do this every time?
strncpy(in.ifopts.ifr_name, in.ifName, IFNAMSIZ-1); // set if name
ioctl(in.sockfd, SIOCGIFFLAGS, &in.ifopts); // get current flags
in.ifopts.ifr_flags |= IFF_PROMISC; // set promiscuous mode
ioctl(in.sockfd, SIOCSIFFLAGS, &in.ifopts); // write flags
// get my mac addr
//ioctl(in.sockfd,SIOCGIFHWADDR,&in.ifopts);
//memcpy(in.mac,in.ifopts.ifr_hwaddr.sa_data,ETH_ALEN);
// find Interface index
strncpy(in.ifopts.ifr_name, in.ifName, IFNAMSIZ-1); //
ioctl(in.sockfd, SIOCGIFINDEX, &in.ifopts); // get if index
in.socketaddress.sll_ifindex=in.ifopts.ifr_ifindex; // set index to sockaddr_ll
// Allow the socket to be reused - incase connection is closed prematurely
if (setsockopt(in.sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
perror("setsockopt");
close(in.sockfd);
exit(EXIT_FAILURE);
}
// Bind to device
if (setsockopt(in.sockfd, SOL_SOCKET, SO_BINDTODEVICE, in.ifName, IFNAMSIZ-1) == -1) {
perror("SO_BINDTODEVICE");
close(in.sockfd);
exit(EXIT_FAILURE);
}
// -----------------------------------
// Now, do the OUT Interface
// -----------------------------------
memset(&out.socketaddress, 0, sizeof(struct sockaddr_ll)); // clear Var
out.socketaddress.sll_family = PF_PACKET;
out.socketaddress.sll_protocol = htons(ETH_P_ALL); // just dummy, don't needed
out.socketaddress.sll_halen = ETH_ALEN;
// Open PF_PACKET socket, listening for EtherType ETHER_TYPE */
if ((out.sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("listener: socket");
exit(EXIT_FAILURE);
}
memset (&out.ifopts, 0, sizeof (struct ifreq));
// Set interface to promiscuous mode - do we need to do this every time? */
strncpy(out.ifopts.ifr_name, out.ifName, IFNAMSIZ-1);
ioctl(out.sockfd, SIOCGIFFLAGS, &out.ifopts);
out.ifopts.ifr_flags |= IFF_PROMISC;
ioctl(out.sockfd, SIOCSIFFLAGS, &out.ifopts);
// get my mac addr
// ioctl(out.sockfd,SIOCGIFHWADDR,&out.ifopts);
// memcpy(out.mac, out.ifopts.ifr_hwaddr.sa_data, ETH_ALEN);
// find Interface index */
strncpy(out.ifopts.ifr_name, out.ifName, IFNAMSIZ-1);
ioctl(out.sockfd, SIOCGIFINDEX, &out.ifopts);
out.socketaddress.sll_ifindex=out.ifopts.ifr_ifindex;
// Allow the socket to be reused - incase connection is closed prematurely */
if (setsockopt(out.sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
perror("setsockopt");
close(out.sockfd);
exit(EXIT_FAILURE);
}
// Bind to device */
if (setsockopt(out.sockfd, SOL_SOCKET, SO_BINDTODEVICE, out.ifName, IFNAMSIZ-1) == -1) {
perror("SO_BINDTODEVICE");
close(out.sockfd);
exit(EXIT_FAILURE);
}
// Working LOOP
// interface in
// buffer structur
// ------------------------------------------------------------
// | dest | source | len | recv packet |
// ------------------------------------------------------------
// ^InTunnelPtr ^ InPtr
repeat:
numbytes=0;
numbytes = recvfrom(in.sockfd, &InBuf[14], BUF_SIZ, 0, NULL, NULL) ;
/* let the game begin */
// test multicast addresses here
// and do something:-)
if (numbytes > 0) {
/* if (memcmp(InPtr->ether_dhost,CISCOSHARED_STP, ETH_ALEN) == 0) {
if (debug == 1) printf("Cisco Shard stp found");
}
else if (memcmp(InPtr->ether_dhost,IEEE802_1AD_STP, ETH_ALEN)==0) {
if ( debug == 1) printf("IEEE802.1AD stp found");
}
else */
if (memcmp(InPtr->ether_dhost,IEEE802_1D_STP, ETH_ALEN)==0) // this tunnel
{
if (debug == 1) printf("IEEE802.1D stp for tunnel eth1\n");
memcpy(InTunnelPtr->ether_dhost,PeerMac , ETH_ALEN); // Copy PeerMac to destination address
memcpy(InTunnelPtr->ether_shost,myMac , ETH_ALEN); // Copy my peer mac to source address
InTunnelPtr->ether_type=numbytes+14; // set tunnel header len
// if (numbytes = sendto(out.sockfd, &InBuf[0] , (numbytes+14), 0,(struct sockaddr_ll *)&out.socketaddress,sizeof(out.socketaddress)) < 0)
i = numbytes+14;
if (numbytes = sendall_eth1(out.sockfd, &InBuf[0] , &i, &out.socketaddress, sizeof(out.socketaddress)) < 0)
{
printf("send error %s \n",strerror(errno));
}
} else { // send untunneled packet out
if (debug == 1) printf ("send untunneled packet eth1\n");
// if (numbytes = sendto(out.sockfd, &InBuf[14], numbytes, 0,(struct sockaddr_ll *)&out.socketaddress,sizeof(out.socketaddress)) < 0)
i = numbytes;
if (numbytes =
sendall_eth1(out.sockfd, &InBuf[14], &i, &out.socketaddress, sizeof(out.socketaddress)) < 0)
{
printf("send error %s \n",strerror(errno));
}
}
}
goto repeat