UDP packets visible in wireshark are not captured in Windows sockets (even with raw sockets) - sockets

I have a board (with FPGA) connecting to a windows 10 host through a 10G NIC. The board is set to static IP 10.254.210.10 & the host is 10.254.210.11. I can see the UDP packets in wireshark but it is not pass through to the sockets.
UDP packet not able to capture through socket
a) I tried UDP server with socket bind to INADDR_ANY and port 2222. The host has another WI-FI NIC(192.168.x.x). We can capture the packet through sockets when it is entering through this interface. So, I guess it is not a firewall issue.
UDP packet able to capture through socket
b) I created a raw socket but still couldn't capture the packet observed in wireshark.
Enabled promiscuous mode.
// enable promiscuous mode
DWORD dwValue = RCVALL_ON;
DWORD dwBytesReturned = 0;
if (WSAIoctl(s, SIO_RCVALL, &dwValue, sizeof(dwValue), NULL, 0, &dwBytesReturned, NULL, NULL) == SOCKET_ERROR)
{
sprintf(err_msg, "Error to set in promiscous mode: WSAIoctl returned error code %d\n", WSAGetLastError());
printf("Ioctl failed with error code : %d", WSAGetLastError());
fwrite(err_msg, sizeof(err_msg), 1, fp);
closesocket(s);
WSACleanup();
exit(EXIT_FAILURE);
}
puts("Ioctl done\n");
c) netstat doesn't show any errors in "UDP STatistics for IPv4"
d) Both IP checksum and UDP checksum is set to 0000 (i.e disabled).

Related

Binding to UDP socket *from* a specific IP address

I have packets coming from a specific device directly connected to my machine. When I do a tcpdump -i eno3 -n -n, I can see the packets:
23:58:22.831239 IP 192.168.0.3.6516 > 255.255.255.255.6516: UDP, length 130
eno3 is configured as 192.168.0.10/24
When I set the socket the typical way:
gOptions.sockfd = socket(AF_INET, SOCK_DGRAM, 0);
memset((void *)&gOptions.servaddr, 0, sizeof(struct sockaddr_in));
gOptions.servaddr.sin_family = AF_INET;
inet_pton(AF_INET, gOptions.sourceIP, &(gOptions.servaddr.sin_addr));
gOptions.servaddr.sin_port = htons(gOptions.udpPort);
bind(gOptions.sockfd, (struct sockaddr *)&gOptions.servaddr, sizeof(struct sockaddr_in));
And I use the sourceIP of "255.255.255.255" on port "6516" - it connects and reads.
What I want to do, however, is bind such that I am limiting my connection from the source IP - "192.168.0.3". I have figured out how to connect on the device using either device name ("eno3") of the iface of that device ("192.168.0.10") - but that doesn't help as I may have multiple devices connected to "192.168.0.10" that blab on that port, but I only want the packets from 192.168.0.3 for port 6516.
I thought s_addr - part of sin.addr - was the source IP... but it is not.
You can't bind() to a remote IP/port, only to a local IP/port. So, for what you have described, you need to bind() to the IP/port where the packets are being sent to (192.168.0.10:6516).
Now, you have two options to choose from. You can either:
use recvfrom() to receive packets, using its src_addr parameter to be given each sender's IP/port, and then you can discard packets that were not sent from the desired sender (192.168.0.3:6516).
or, use connect() to statically assign the desired sender's IP/port (192.168.0.3:6516), and then you can use recv() (not recvfrom()) to receive packets from only that sender.

Can I write() to a socket just after connect() call, but before TCP connection established?

My experiment showed that I can write to a non-blocking socket just after the connect() call, with no TCP connection established yet, and the written data correctly received by the peer after connection occured (asynchronously). Is this guaranteed on Linux / FreeBSD? I mean, will write() return > 0 when the connection is still in progress? Or maybe I was lucky and the TCP connection was successfully established between the connect() and write() calls?
The experiment code:
int fd = socket (PF_INET, SOCK_STREAM, 0);
fcntl(fd, F_SETFL, O_NONBLOCK)
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(_ip_port.port);
addr.sin_addr.s_addr = htonl(_ip_port.ipv4);
int res = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
// HERE: res == -1, errno == 115 (EINPROGRESS)
int r = ::write(fd, "TEST", 4);
// HERE: r == 4
P.S.
I process multiple listening and connecting sockets (incoming and outgoing connections) in single thread and manage them by epoll. Usually, when I want to create a new outgoing connection, I call non-blocking connect() and wait the EPOLLOUT (epoll event) and then write() my data. But I noticed that I can begin writing before the EPOLLOUT and get appropriate result. Can I trust this approach or should I use my old fashion approach?
P.P.S.
I repeated my experiment with a remote host with latency 170ms and got different results: the write() (just after connect()) returned -1 with errno == EAGAIN. So, yes, my first experiment was not fair (connecting to fast localhost), but still I think the "write() just next to connect()" can be used: if write() returned -1 and EAGAIN, I wait the EPOLLOUT and retry writing. But I agree, this is dirty and useless approach.
Can I write() to a socket just after connect() call, but before TCP connection established?
Sure, you can. It's just likely to fail.
Per the POSIX specification of write():
[ECONNRESET]
A write was attempted on a socket that is not connected.
Per the Linux man page for write():
EDESTADDRREQ
fd refers to a datagram socket for which a peer address has
not been set using connect(2).
If the TCP connect has not completed, your write() call will fail.
At least on Linux, the socket is marked as not writable until the [SYN, ACK] is received from the peer. This means the system will not send any application data over the network until the [SYN, ACK] is received.
If the socket is in non-blocking mode, you must use select/poll/epoll to wait until it becomes writable (otherwise write calls will fail with EAGAIN and no data will be enqueued). When the socket becomes writable, the kernel has usually already sent an empty [ACK] message to the peer before the application has had time to write the first data, which results in some unnecessary overhead due to the API design.
What appears to be working is to after calling connect on a non-blocking socket and getting EINPROGRESS, set the socket to blocking and then start to write data. Then the kernel will internally first wait until the [SYN, ACK] is received from the peer and then send the application data and the initial ACK in a single packet, which will avoid that empty [ACK]. Note that the write call will block until [SYN, ACK] is received and will e.g. return -1 with errno ECONNREFUSED, ETIMEDOUT etc. if the connection fails. This approach however does not work in WSL 1 (Windows Subsystem for Linux), which just fails will EPIPE immediately (no SIGPIPE though).
In any case, not much can be done to eliminate this initial round-trip time due to the design of TCP. If the TCP Fast Open (TFO) feature is supported by both endpoints however, and can accept its security issues, this round-trip can be eliminated. See https://lwn.net/Articles/508865/ for more info.

Can I detect whether an UDP-socket or a connected UDP socket is used?

Can I detect whether a client application uses an UDP-socket or a connected UDP-socket?
If yes, how? If no, why?
As I said in my comment above, code call connect on a UDP socket. That enforces only traffic to/from the connection address is allowed (and all other packets get dropped) and allows you to use send instead of sendto, but the traffic is still UDP.
But you can use the netstat command from the command line to see if the datagram socket has a remote address association:
For example, imagine if the code did this:
// create a datagram socket that listens on port 12345
sock = socket(AF_INET, SOCK_DGRAM, 0);
port = 12345;
addrLocal.sin_family = AF_INET;
addrLocal.sin_port = htons(port);
result = bind(sock, (sockaddr*)&addrLocal, sizeof(addrLocal));
// associate the socket only with packets arriving from 1.2.3.4:6666
addrRemote.sin_family = AF_INET;
addrRemote.sin_port = htons(6666);
addrRemote.sin_addr.s_addr = ipaddress; // e.g. "1.2.3.4"
result = connect(sock, (sockaddr*)&addrRemote, sizeof(addrRemote));
A corresponding netstat -a -u will reveal the following:
ubuntu#ip-10-0-0-15:~$ netstat -u -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
udp 0 0 ip-10-0-0-15:12345 1.2.3.4:6666 ESTABLISHED
The presence of a value that isn't *:* in the Foreign Address column for the UDP socket will reveal if the socket has connection address associated with it.

tun device: message is not received by server process

I set up two tun devices. The data that is written to each tun device is forwarded over a UDP socket to the other tun device using a simple loop:
// the tuntap device is created using these flags
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
[...]
fd_set fd_list;
FD_ZERO(&fd_list);
FD_SET(fd1, &fd_list); // fd1 is the tun device
FD_SET(fd2, &fd_list); // fd2 is the udp socket
int fds[] = {fd1, fd2};
while(select(max(fd1, fd2)+1, &fd_list, NULL, NULL, NULL) > -1) {
for(i = 0; i < 2; ++i)
if(FD_ISSET(fds[i], &fd_list)) {
nread = read(fds[i], buf, sizeof(buf));
assert(nread > 0);
ret = write(fds[(i+1)%2], buf, nread);
if(ret == -1)
perror("write():");
}
}
After setting up the interfaces using
ifconfig tun0 10.0.0.1
ifconfig tun1 10.0.0.2
I send a ping from one device to the other
ping -I tun1 10.0.0.1
I can see that the IPv4 packet is received by the UDP socket for tun0 and this packet is correctly written to tun0. Also watching the traffic on tun0 using wireshark shows that the packet is received by tun0. However, no ping response packet is created.
I thought that might be a special case for ICMP packets but when I'm using
socat -d -d -d - TCP-LISTEN:2000,so-bindtodevice=tun0 &
sleep 1
echo 2 | socat -d -d -d - TCP:10.0.0.1:2000,so-bindtodevice=tun1
again no connection is established. the connect process (2nd socat call) only continues firing TCP-SYN packets and eventually times out. Again, watching the traffic on tun0 using wireshark shows that the TCP-SYN packet is delivered to the tun0 device.
Why is this packet not forwared to the socat TCP-LISTEN process so it can establish the connection??
Looks like this is a routing error.
When I run the program on two different machines, then the packets are routed through the tun0 device on each machine respectively and http://backreference.org/wp-content/uploads/2010/03/simpletun.tar.bz2 works fine. Running the programm on one machine twice does not work!

Socket remote connection problem C

I wrote a simple server application in C. This server do nothing except print the received message, then exit. Here is the code
int listenfd,connfd,n;
struct sockaddr_in servaddr,cliaddr;
socklen_t clilen;
char *mesg = (char*) malloc(1000*sizeof(char));
listenfd=socket(PF_INET,SOCK_STREAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port=htons(20600);
bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
listen(listenfd,5);
clilen=sizeof(cliaddr);
connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
n = (int) recvfrom(connfd,mesg,1000,0,(struct sockaddr *)&cliaddr,&clilen);
sendto(connfd,mesg,n,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
printf("-------------------------------------------------------\n");
mesg[n] = 0;
printf("Received the following:\n");
printf("%s\n",mesg);
printf("-------------------------------------------------------\n");
close(connfd);
close(listenfd);
I managed to establish a connection using telnet and running
telnet 192.168.1.2 20600
where 192.168.1.2 is the local ip of the server.
The machine runs behind a router ZyXel p-660HW-61 (192.168.0.1).
The problem is I cannot reach the server if I specify the public ip of the machine (151.53.150.45).
I set NAT configuration to the server local ip on all port from 20000 to 21000
http://img593.imageshack.us/img593/3959/schermata20110405a22492.png
port 20600 seems to be open, according to canyouseeme.org/ and yougetsignal.com/tools/open-ports/ (in fact I can read in the console that a packet has been received), but if I run
telnet 151.53.150.45 20600
I get a "Connection Refused" error.
Firewall is disabled, both on the router and on the server machine (that is the same running telnet).
Any help?
If you are typing:
telnet 151.53.150.45 20600
from the LAN rather than from the WAN, then your NAT most probably does not handle hairpin situations properly. This means it only expects you to use the translated address from the WAN.
The solution is check whether you can change the configuration of your NAT to enable usage of translated address on the LAN too (it is sometimes a requirement for P2P systems). If such functionalities are not available, then you need a new NAT.