程序從某些來源獲得misc以太網流量,更改ip並將其重定向到本地主機(例如,它應該用於ssh連接)並從本地主機發回答案。我用下面的代碼:如何使用原始套接字ping本地主機?
int bind_if(int raw , char *device , int protocol) {
struct sockaddr_ll sll;
struct ifreq ifr; bzero(&sll , sizeof(sll));
bzero(&ifr , sizeof(ifr));
strncpy((char *)ifr.ifr_name ,device , IFNAMSIZ);
//copy device name to ifr
if((ioctl(raw , SIOCGIFINDEX , &ifr)) == -1)
{
perror("Unable to find interface index");
return -1;
}
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_protocol = htons(protocol);
if((bind(raw , (struct sockaddr *)&sll , sizeof(sll))) ==-1)
{
perror("bind: ");
return -1;
}
return 0;
}
int _create_input_socket(int *s, char* interface)
{
struct packet_mreq mreq;
struct ifreq if_idx;
int sockopt;
int ifnumber = 0;
if ((*s = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
{
perror("cannot create socket");
return -1;
}
memset(&if_idx, 0, sizeof(struct ifreq));
strncpy(if_idx.ifr_name, interface, IFNAMSIZ-1);
if (ioctl(*s, SIOCGIFINDEX, &if_idx) < 0)
{
perror("SIOCGIFINDEX for interface failed");
close(*s);
return -1;
}
ifnumber = if_idx.ifr_ifindex;
/* Get the current flags that the device might have */
if (ioctl(*s, SIOCGIFFLAGS, &if_idx) <0)
{
perror("SIOCGIFFLAGS failed");
close(*s);
return -1;
}
/* Set the old flags plus the IFF_PROMISC flag */
if_idx.ifr_flags |= IFF_PROMISC;
if (ioctl(*s, SIOCSIFFLAGS, &if_idx) == -1)
{
perror("SIOCSIFFLAGS while adding IFF_PROMISC failed");
close(*s);
}
int flags = fcntl(*s, F_GETFL, 0);
int ret = fcntl(*s, F_SETFL, flags | O_NONBLOCK);
printf("ret = %d\n", ret);
if(ret < 0)
{
perror("fcntl for O_NONBLOCK failed");
close(*s);
return -1;
}
if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) == -1) {
perror("setsockopt SO_REUSEADDR failed");
close(*s);
return -1;
}
if(bind_if(*s, interface, ETH_P_ALL) == -1)
{
close(*s);
return -1;
}
if (setsockopt(*s, SOL_SOCKET, SO_BINDTODEVICE, interface, IFNAMSIZ-1) == -1) {
perror("SO_BINDTODEVICE");
close(*s);
return -1;
}
memset(&mreq,0,sizeof(mreq));
mreq.mr_ifindex = ifnumber;
mreq.mr_type = PACKET_MR_PROMISC;
mreq.mr_alen = 6;
if (setsockopt(*s,SOL_PACKET,PACKET_ADD_MEMBERSHIP,
(void*)&mreq,(socklen_t)sizeof(mreq)) < 0)
perror("setsockopt(PACKET_ADD_MEMBERSHIP)");
printf("create socket %d for iface %s(%d)\n", *s, interface, ifnumber);
return ifnumber;
}
void SendTo(int sock, int ifindex, const unsigned char*buffer, int buffer_size)
{
struct sockaddr_ll socket_address;
memset(&socket_address, 0, sizeof(socket_address));
socket_address.sll_ifindex = ifindex;
socket_address.sll_halen = ETH_ALEN;
socket_address.sll_family = htons(PF_PACKET);
socket_address.sll_protocol = htons(ETH_P_ALL);
socket_address.sll_hatype = ARPHRD_ETHER;
memcpy(socket_address.sll_addr, buffer, 6);
if (sendto(sock, buffer, buffer_size, 0, (struct sockaddr*)&socket_address, sizeof(socket_address)) < 0)
printf("Send failed due error %d\n", errno);
}
某處在main():
ifindex_lo = _create_input_socket(&socket_loopback, "lo");
...
SendTo(socket_loopback, ifindex_lo, buffer, size);
我使用環回接口上的tcpdump檢查它是如何工作的,當我通過程序發送Ping:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes
00:10:24.269431 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 29046, seq 1, length 64
00:10:25.269125 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 29046, seq 2, length 64
當我從linux執行真正的ping命令時:
00:43:49.228192 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 535, seq 1, length 64
00:43:49.228219 IP localhost.localdomain > localhost.localdomain: ICMP echo reply, id 535, seq 1, length 64
00:43:50.227183 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 535, seq 2, length 64
00:43:50.227203 IP localhost.localdomain > localhost.localdomain: ICMP echo reply, id 535, seq 2, length 64
我檢查了數據包 - 其外觀與icmp序列號相同。所有其他流量也是如此:系統不會回覆我的程序生成的流量,但會根據其他來源生成的流量進行回覆。我對loopback接口上sendto的這種行爲感到困惑。任何人都知道如何避免這一點?
我相信,你需要root權限才能使用原始套接字。嘗試sudo'ing您的程序。 – KBart
感謝您的回答,但我在目標機器上使用了archlinux的root帳戶,在這種情況下,應該沒有任何priveleges問題。 – user2890160
如果我理解你是正確的,你可以在數據包頭中更改IP。如果是這樣,您需要重新計算新數據包的校驗和。如果數據包的校驗和不正確,目標機器可以放棄它。 – fycth