The program got misc ethernet traffic from some source, change ip and should redirect it to localhost(for example, it should be used for ssh connection) and send answers from localhost back. I used following code:
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);
}
Somewhere in main():
ifindex_lo = _create_input_socket(&socket_loopback, "lo");
...
SendTo(socket_loopback, ifindex_lo, buffer, size);
I used tcpdump on loopback interface to check how it works, when I send ping through program:
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
And when I perform real ping from linux command:
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
I checked packets - its looks the same except icmp sequence numbers. The same situation is with all other traffic: system does not reply to traffic generated by my program, but make reply by traffic generated by other sources. I am confused for such behavior of sendto on loopback interface. Anyone have idea how avoid that?
Try examining the complete packets, including ethernet header ( -e to tcpdump) and make sure those are correct.
I think struct sockaddr_ll.sll_protocol set to ETH_P_ALL in SendTo()might be messing up your packets. Having the wrong protocol would explain why they are not delivered to the appropriate protocol handler.
Try removing everything except the struct sockaddr_ll.sll_family and struct sockaddr_ll.sll_ifindex from the SendTo(). In case that does not work, manually set .sll_protocol as the type you are sending out. The man-page could be interpreted as saying that sll_protocol has no influence when the socket is SOCK_RAW but I think it might.
man 7 packet:
When you send packets it is enough to specify sll_family,
sll_addr, sll_halen, sll_ifindex. The other fields should be 0.
sll_hatype and sll_pkttype are set on received packets for your
information. For bind only sll_protocol and sll_ifindex are
used.
You could post all of the code you are using, but it is already rather long. It would be best, if you put together a very short program, that exhibits the same symptoms and post that.
Related
I am trying to create multiple TUN devices to tunnel the multi-device traffic through a common physical interface.
This is the schema I have:
Socket 1 is sending traffic through tun1 with destiny IP 1.1.1.2 and Socket 2 is doing the same on the other interface.
I have a program running between both TUN devices and the physical interface (eth0) that encapsulates IP packets from the TUN devices into UDP packets and then it sends them to the server. The server unpacks the received packets and answers both clients with echo packets (also encapsulated).
When those packets arrive in eth0, another program reads the packets and forwards them to its TUN device. After that, both programs that are running behind the sockets are blocked on recv() function waiting for the server answer on tunX devices. However, it seems like the kernel is discarding those packets on the TUN devices even when they are well-formed.
I tried by change the netmask of both interfaces to 255.255.255.0 and then only one of the sockets receives correctly the answer.
All this software has been written in C.
This is the function to create a new TUN device:
#define MTU_SIZE 1500
#define SUBNET_MASK 0xFFFFFFFF
int open_tun_iface(char * name, uint8_t * ip)
{
int sock;
struct ifreq ifr_tun;
struct sockaddr_in * sa;
int tunfd = tun_init(name, &ifr_tun, IFF_TUN | IFF_NO_PI);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("Open socket");
tun_close(tunfd);
return -1;
}
/* Set tun IP */
if (set_ip(&ifr_tun, sock, ip) < 0) {
tun_close(tunfd);
return -1;
}
sa = (struct sockaddr_in *)&ifr_tun.ifr_netmask;
memset(sa,0,sizeof(*sa));
sa->sin_family = AF_INET;
sa->sin_addr.s_addr = htonl(SUBNET_MASK);
/* Set the mask */
if (ioctl(sock, SIOCSIFNETMASK, &ifr_tun) < 0)
{
perror("SIOCSIFNETMASK");
tun_close(tunfd);
close(sock);
return -1;
}
/* Read flags */
if (ioctl(sock, SIOCGIFFLAGS, &ifr_tun) < 0) {
perror("SIOCGIFFLAGS");
tun_close(tunfd);
close(sock);
return -1;
}
/* Set Iface up and flags */
ifr_tun.ifr_flags |= IFF_UP;
ifr_tun.ifr_flags |= IFF_RUNNING;
if (ioctl(sock, SIOCSIFFLAGS, &ifr_tun) < 0) {
perror("SIOCGIFFLAGS");
tun_close(tunfd);
close(sock);
return -1;
}
/* Set MTU size */
ifr_tun.ifr_mtu = MTU_SIZE;
if (ioctl(sock, SIOCSIFMTU, &ifr_tun) < 0) {
perror("SIOCSIFMTU");
tun_close(tunfd);
close(sock);
return -1;
}
close(sock);
return tunfd;
}
The function that reads packets from eth0 and forward them to the correct TUN interface is the following one:
void * downlink_distributor(void * args)
{
uint8_t buffer[BUFFER_DATA_LEN];
struct sockaddr_in spgw_addr;
int sockfd;
int sockaddr_len = sizeof(spgw_addr);
int len, packet_len, teid;
eNB * enb = (eNB *) args;
sockfd = get_spgw_socket(enb);
while(1)
{
/* Read packets from the server */
len = recvfrom(sockfd, buffer, BUFFER_DATA_LEN, 0, ( struct sockaddr *) &spgw_addr, (socklen_t *)&sockaddr_len);
if(len < 0)
{
perror("recv downlink_distributor");
return NULL;
}
/* Get the TEID that identifies the TUN device */
teid = analyze_gtp_header(buffer, &packet_len);
if(teid > -1)
{
/* Write the packet in the TUN device associated with the packet TEID */
tun_write(get_tun_device(tun_descriptors[teid % MAX_TUN_DESCRIPTORS]), buffer + 8, packet_len);
}
}
return NULL;
}
Finally, this is the function that is running on both sockets and generate some traffic:
void * _generate_udp_traffic(void * args)
{
uint8_t buffer[BUFFER_DATA_LEN];
struct sockaddr_in dest_addr, spgw_addr;
fd_set fds;
struct timeval timeout;
int retval;
timeout.tv_sec = 0;
timeout.tv_usec = 1;
int tunfd;
char msg[] = "Uplink traffic";
int sockfd;
int len;
int sockaddr_len = sizeof(dest_addr);
udp_generator gen;
/* Copy args */
memcpy(&gen, args, sizeof(udp_generator));
free(args);
/* Get TUN device */
tunfd = get_tun_device(gen.ue);
/* Get UE data socket (TUN socket) */
sockfd = get_data_plane_socket(gen.ue);
/* Configure destiny address */
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(gen.port_dest);
memcpy((void*) &dest_addr.sin_addr.s_addr, gen.dest_ip, sizeof(struct in_addr));
/* Configure SPGW address */
memset(&spgw_addr, 0, sizeof(spgw_addr));
spgw_addr.sin_family = AF_INET;
spgw_addr.sin_port = htons(S1_U_PORT);
memcpy((void*) &spgw_addr.sin_addr.s_addr, get_spgw_ip(gen.ue), sizeof(struct in_addr));
while(1)
{
sendto(sockfd, msg, strlen(msg), 0, (const struct sockaddr *) &dest_addr, sizeof(dest_addr));
while(1)
{
FD_ZERO(&fds);
FD_SET(tunfd, &fds);
retval = select(tunfd+1, &fds, 0, 0, &timeout);
if (retval == -1){
perror("select()");
}
else if (retval){
/* Reuse of the buffer with enough space for the GTP header */
len = tun_read(tunfd, buffer+8, BUFFER_DATA_LEN); /* We call read to clean the buffer from external traffic */
/* Detect IPv4 packets*/
if((buffer[8] & 0xF0) == 0x40)
{
generate_gtp_header(buffer, gen.ue, len);
break;
}
}
}
/* Protect the access to the eNB socket with a lock*/
pthread_mutex_lock(&lock);
/* Send tho the SPGW */
sendto(get_spgw_socket(gen.enb), buffer, len+8, 0, (const struct sockaddr *) &spgw_addr, sizeof(spgw_addr));
/* Unlock the mutex */
pthread_mutex_unlock(&lock);
/* Receive server answer listening on the TUN device */
len = recvfrom(sockfd, buffer, BUFFER_DATA_LEN, 0, ( struct sockaddr *) &dest_addr, (socklen_t *)&sockaddr_len);
printf("UE %d has received: %s\n", get_ue_id(gen.ue), buffer);
/* Sleep 5 seconds */
sleep(5);
}
return NULL;
}
If the netmask is 32 both programs that are generating client traffic get blocked on recvfrom() inside _generate_udp_traffic function. If I set both netmask to 24 only one of them receive the answer from the server and the other gets stuck at recvfrom.
How can I configure both TUN devices to make both attached sockets work correctly?
UPDATE: I think that my problem is a kernel route table problem. If I use just one socket, I only receive traffic with netmask <= 30. With a netmask of 32, I can see that the server answer is introduced correctly on the TUN interface but somehow, the socket that is blocked in recv() does not receive anything.
im playing around with STP packets and writing a program raw sockets to modify them.
Reading fropm eth0 sending to eth1. System is ubuntu 14.10/ Kernel 3.somewhat.
Packets are generated with additional computers with Karat and Wireshark is running this interfaces too.
Inject a packet and after first run recvfrom didn't stop. Read the same packet from eth0
and send it to eth1. Debugging session ???????
The final edition should read all frame from eth0 , forward all and put all STP in a "unicast tunnel" - Read alle eth1 frame an forward eth0 and "unpack" special "Tunnel"
frames.
i put some code here:
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
Lets say that I have a buffer with IP message (SYN / ACK or whatever), all headers - TCP and IP are filled and so on. I want to send it through raw socket.
When I execute this
void send_ip(void* data, u16_t len) {
std::cout << "begine of send_ip" << std::endl;
int s;
struct sockaddr_in dst_addr;
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
const int hdrincl = 1;
setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hdrincl, sizeof(hdrincl));
dst_addr.sin_family = AF_INET;
dst_addr.sin_port = 6667;
inet_aton("172.17.9.71", &dst_addr.sin_addr);
std::cout << "before send in send_ip, len = " << (u16_t)len << std::endl;
if (sendto(s, data, len, 0,
(struct sockaddr *)&dst_addr, (socklen_t)sizeof(dst_addr)) < 0) {
perror("sendto ERROR :");
}
else{
}
}
I get
sendto ERROR :: Invalid argument
When I change it to
s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)
And take away
setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hdrincl, sizeof(hdrincl));
I get OK for sending, but in Wireshark there is a message
110539 1059.796163000 172.17.9.210 172.17.9.71 TCP 78 65535 > 65535 [SYN, RST,
Reserved] Seq=0 Win=1, bogus TCP header length (0, must be at least 20)
So the message goesn't go to the server. What do I do wrong?
Thanks.
Please any one could help on this issue. Please
In the below sample code,we had bind raw sock with eth0. but while running the program
the recvfrom of raw sock is receiving packets from eth0 & eth1 on same machine(xx_86).
It is not clear to me why,could help one on this issue.
I hope the setsockopt is not working properly
OS: Fedora core 6(2.6.18-1.2798.fc6)
Sampe code:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <linux/filter.h>
#include <sys/ioctl.h>
#include <string.h>
#include <arpa/inet.h>
int main(int argc, char **argv) {
int sock, i;
unsigned char buffer[2048];
unsigned char tbuff[2048];
unsigned char *iphead, *ethhead,*phead;
struct ifreq ethreq;
// NOTE: use TCPDUMP to build the filter array.
// set filter to sniff only port 443
// $ sudo tcpdump -dd port 443
// raw for recvfrom eth0
if ((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1) {
perror("socket");
exit(1);
}
// set network card to promiscuos
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
if (ioctl(sock,SIOCGIFFLAGS, ðreq) == -1) {
perror("ioctl");
close(sock);
exit(1);
}
ethreq.ifr_flags |= IFF_PROMISC;
if (ioctl(sock, SIOCSIFFLAGS, ðreq) == -1) {
perror("ioctl");
close(sock);
exit(1);
}
//bind to sock with eth0
struct ifreq Interface;
memset(&Interface, 0, sizeof(Interface));
strncpy(Interface.ifr_ifrn.ifrn_name, "eth0", IFNAMSIZ);
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &Interface, sizeof(Interface)) < 0) { close(sock); }
//open the RAW socket for sendto
int s = socket (PF_INET, SOCK_RAW, IPPROTO_RAW);
struct sockaddr_in sin;
memset(&sin,0,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(0);
sin.sin_addr.s_addr = inet_addr ("10.3.161.104");
// inform kernal don't fill IP and Transport header
int one = 1;
const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
printf ("Warning: Cannot set HDRINCL!\n");
//bind the sock descriptor with eth0
struct ifreq Interface1;
memset(&Interface1, 0, sizeof(Interface1));
strncpy(Interface1.ifr_ifrn.ifrn_name, "eth0", IFNAMSIZ);
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &Interface1, sizeof(Interface1)) < 0) { close(s); }
while (1) {
printf("----------------------\n");
i = recvfrom(sock, buffer, sizeof(buffer), 0, NULL, NULL);
printf("%d bytes read\n", i);
// check header size: Ethernet = 14, IP = 20, TCP = 8 (sum = 42)
if (i < 42) {
perror("recvfrom():");
printf("Incomplete packet (errno is %d)\n", errno);
close(sock);
exit(0);
}
phead = buffer + 14; // (skip ethernet header)
memcpy(tbuff,phead,i-14);
iphead=tbuff;
if (*iphead == 0x45) {
int ptrindex= iphead[9];
switch(ptrindex){
case 1:
printf("The transport protocl is:ICMP\n");
break;
case 2:
printf("The transport protol is:IGMP\n");
break;
case 6:
printf("The transport protocol is:TCP\n");
break;
case 17:
printf("The transport protocol is:UDP\n");
break;
case 103:
printf("The transport protocol is:PIM\n");
break;
default:
printf("The transport protocol is:%d\n",iphead[9]);
}
//printf("%d",*ptrindex);
// printf("\n The transport protocol is :%u\n",iphead[9]);
printf("Source Address: %d.%d.%d.%d, Port: %d\n",
iphead[12], iphead[13], iphead[14], iphead[15], (iphead[20] << 8) + iphead[21]);
printf("Dest Address: %d.%d.%d.%d, Port: %d\n",
iphead[16], iphead[17], iphead[18], iphead[19], (iphead[22] << 8) + iphead[23]);
if(sendto(s,tbuff,i-14,0,(struct sockaddr *)&sin,sizeof(sin))<0)
printf("error\n");
else{printf("\nThe received packet is send\n");}
memset(buffer,0,sizeof(buffer));
memset(tbuff,0,sizeof(tbuff));
}
else{ printf("The non ip had received");}
}
close(sock);
}
In the linux man page (http://linux.die.net/man/7/socket) :
SO_BINDTODEVICE
Bind this socket to a particular device like "eth0", as specified in the passed interface name. If the name is an empty string or the option length is zero, the socket device binding is removed. The passed option is a variable-length null-terminated interface name string with the maximum size of IFNAMSIZ. If a socket is bound to an interface, only packets received from that particular interface are processed by the socket. Note that this only works for some socket types, particularly AF_INET sockets. It is not supported for packet sockets (use normal bind(2) there).
So, try the bind instead.
Thanks all,thanks you very much for valuable time. it is worked with bind approach
The code segments had helped me.
setsockopt() is bug in the fedora 2.6.18
alternative approach is below.
void BindToInterface(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");
exit(-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: ");
exit(-1);
}
return 0;
}
I have to write a trceroute script but I'm not sure if my attempts are correct.
Right now I'm doing it like that (please correct me if I'm doing wrong or clumsy):
Got an struct for ip- and udpheader
A checksum function
Opening 2 sockets: One for sending UDP-packets in SOCK_RAW mode (to manipulate ttl) and one to receive ICMP-answers from the routers.
Using sendto() to send UDP packet
Having no clue how to receive and process an ICMP answer
Are there any more comfortable ways to change the TTL than using sock_raw where I have to define all header stuff by myself?
What parameters should I use for socket() when opening ICMP sock?
How to receive the ICMP answer?
What platform are you targeting? Here's a BSD flavor from OpenBSD source:
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
err(5, "icmp socket");
if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
err(5, "raw socket");
On Linux, I believe, you need to use IP_RECVERR and recvmsg(2) with the MSG_ERRQUEUE, see ip(7).
As far as setting the TTL is concerned, you can use setsockopt(). Here's an extract from the iputils' source for ping on Linux:
if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 1) == -1) {
perror ("ping: can't set multicast time-to-live");
exit(2);
}
if (setsockopt(icmp_sock, IPPROTO_IP, IP_TTL, &ittl, sizeof(ittl)) == -1) {
perror ("ping: can't set unicast time-to-live");
exit(2);
}
I met the same problem and solved it.
You need to
create a new socket using ICMP protocol
bind to a specific port like 33434
receive ICMP reply.
I will show my code.
// ......create sending socket and fill the udp data...
// create socket to receive ICMP reply
SOCKET sock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,
WSA_FLAG_OVERLAPPED);
// from for receiving data about routing server
SOCKADDR_IN server_addr, from;
int fromlen = sizeof(from);
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(33434);
// Set the receive and send timeout values to a second
timeout = 1000;
ret = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
sizeof(timeout));
if (ret == SOCKET_ERROR) {
printf("setsockopt(SO_RCVTIMEO) failed: %d\n", WSAGetLastError());
return -1;
}
timeout = 1000;
ret = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
sizeof(timeout));
if (ret == SOCKET_ERROR) {
printf("setsockopt(SO_SNDTIMEO) failed: %d\n", WSAGetLastError());
return -1;
}
// bind to the port 33434
int err = bind(sock, (SOCKADDR *)&server_addr, sizeof(SOCKADDR));
if (err != 0) {
fprintf(stderr, "bind with error: %d\n", WSAGetLastError());
return 3;
}
for (ttl = 1; ((ttl < maxhops) && (!done)); ttl++) {
int bwrote;
// Set the time to live option on the socket
set_ttl(sockRaw, ttl);
// Fill in some more data in the UDP header
((UdpHeader *)udp_data)->length = 8;
((UdpHeader *)udp_data)->dest_port = htons(33434);
((UdpHeader *)udp_data)->source_port = htons(33434);
((UdpHeader *)udp_data)->checksum =
checksum((USHORT *)udp_data, datasize);
// Send the UDP packet to the destination
bwrote = sendto(sockRaw, udp_data, datasize, 0, (SOCKADDR *)&dest,
sizeof(dest));
if (bwrote == SOCKET_ERROR) {
if (WSAGetLastError() == WSAETIMEDOUT) {
printf("%2d Send request timed out.\n", ttl);
continue;
}
printf("sendto() failed: %d\n", WSAGetLastError());
return -1;
}
// Read a packet back from the destination or a router along the way.
ret = recvfrom(sock, recvbuf, MAX_PACKET, 0, (struct sockaddr *)&from,
&fromlen);
if (ret == SOCKET_ERROR) {
if (WSAGetLastError() == WSAETIMEDOUT) {
printf("%2d Receive Request timed out.\n", ttl);
continue;
}
printf("recvfrom() failed: %d\n", WSAGetLastError());
return -1;
}
/* Decode the response to see if the ICMP response is from a router
* along the way or whether it has reached the destination. */
done = decode_resp(recvbuf, ret, &from, ttl);
Sleep(1000);
}
and it works on my computer. (Windows 10)
the result in my computer