Linux UDP Socket sendto: Operation not Permitted - c

I'm trying to diagnose a problem with the OpenSIPS ( a SIP proxy ) application.
When sending two different UDP packets to the same IP and port, one call fails with -1 EPERM (Operation not permitted) whilst the other is fine.
Both of the calls are made from the same process ( at least the same PID ).
The code in question is on github.
Here's the strace output:
strace -e sendto
sendto(7, "SIP/2.0 100 Giving a try\r\nVia: S"..., 315, 0, {sa_family=AF_INET, sin_port=htons(5060), sin_addr=inet_addr("yyy.yyy.yyy.yyy")}, 16) = 315
sendto(7, "INVITE sip:myHomeDesktop#xxx"..., 1253, 0, {sa_family=AF_INET, sin_port=htons(5060), sin_addr=inet_addr("xxx.xxx.xxx.xxx")}, 16) = 1253
sendto(7, "SIP/2.0 200 OK\r\nVia: SIP/2.0/UDP"..., 707, 0, {sa_family=AF_INET, sin_port=htons(5060), sin_addr=inet_addr("yyy.yyy.yyy.yyy")}, 16) = -1 EPERM (Operation not permitted)

It turns out that the kernel conntrack modules were dropping the packet, leading to the syscall getting the EPERM error and not sending the packets.
I found this after looking at the syslog and finding:
May 26 10:59:45 localhost kernel: nf_ct_sip: dropping packet: cannot add expectation for voice
I was completely unaware that I was using the sip conntrack module, and it's not dynamically loaded on my system (lsmod shows blank).
I circumvented the problem by turning off connection tracking for my SIP traffic with:
iptables -I OUTPUT -t raw -p udp --sport 5060 -j CT --notrack
iptables -I PREROUTING -t raw -p udp --dport 5060 -j CT --notrack

Related

How to fix `EPERM` error when trying to use `sendto()` with Ethernet `socket(AF_INET, ..., ...)` (IP output packets) on Linux

Here is a massively reduced code sample, following my code from my eRCaGuy_hello_world repo here as a pattern: socket__geeksforgeeks_udp_client_GS_edit_GREAT.c:
#define SOCKET_TYPE_UDP_IPV4 AF_INET, SOCK_DGRAM, 0
// Create an IPv4 UDP socket to send Ethernet packets out to a connected device
int socket_fd = socket(SOCKET_TYPE_UDP_IPV4);
// Send a packet via `sendto()`
const char msg_to_send[] = "Hello from client.";
ssize_t num_bytes_sent = sendto(socket_fd, msg_to_send, sizeof(msg_to_send), 0,
(const struct sockaddr *)&addr_server, sizeof(addr_server));
if (num_bytes_sent == -1)
{
printf("Failed to send to server. errno = %i: %s\n", errno, strerror(errno));
goto cleanup;
}
sendto() fails, however, with the num_bytes_sent return code set to -1 and errno set to EPERM. EPERM stands for "permissions error: 'E'rror 'PERM'issions". A list of all possible errno errors can be found here: https://man7.org/linux/man-pages/man3/errno.3.html. It shows:
EPERM Operation not permitted (POSIX.1-2001).
However, none of the 3 reference pages I have for the sendto() function show EPERM as a valid or even possible error condition for calling this function! Here are the 3 reference pages I have for sendto(). See the "ERRORS" or "RETURN VALUE" section of each of them:
POSIX Programmer's Manual for sendto(): https://man7.org/linux/man-pages/man3/sendto.3p.html
man7.org "Linux Programmer's Manual" for sendto(): https://man7.org/linux/man-pages/man2/send.2.html
Linux.die.net manual for sendto(): https://linux.die.net/man/2/sendto
So, what's happening and how do I fix it? I'd like sendto() to work so I can send out an Ethernet UDP packet to a connected device. On other machines it works fine, but from my embedded Linux board it fails with EPERM.
How to fix EPERM (permissions error; 'E'rror 'PERM'issions) by disabling the firewall
After a ton of study, googling, testing on an embedded Linux board, etc, I've determined it's simply because I have a firewall up blocking my outgoing traffic. Do this to disable the firewall, then try again, and the EPERM error will go away:
# Manually disable the firewall
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -t filter --flush
One source that helped me conclude this was the problem, for instance, was Dmitry V. Krivenok here: UDP socket && sendto && EPERM (emphasis added):
The program works fine when I poll few hundred of devices,
but I get strange error when I poll several thousand of devices:
sendto returns -1 with errno set to EPERM (Operation not permitted).
sendto (2) manual page doesn't say anything about EPERM
error.
I searched through the google and found, that sendto may
fail with errno == EPERM if local firewall disallows outgoing UDP
packets.
See also:
https://stackoverflow.com/a/73302873/4561887
Google search for "socket EPERM"
Google search for "socket sendto EPERM"

Can I ping with Tun/Tap interface

I am learning routing with tuntap interfaces... and I had created a tun0 interface and configured Ip address with ifconfig command on different subnet and adding the gateway with ip route command and I have also used masquerading rule ...
my doubt is can i ping with tuntap interface or they are only used to route the traffic or something I don't know about these interface or may be misconfiguration..
May be this question sounds me new bie and I am but give please give me correct direction..
Ok Gerhardh,
Edit: I had created tun dev like this:
int tun_dev_alloc()
{
struct ifreq ifr;
int tun_dev_fd , ioctl_err;
if((tun_dev_fd = open("/dev/net/tun",O_RDWR)) < 0)
{
perror("Can't open /dev/net/tun");
return tun_dev_fd;
}
memset(&ifr,0,sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_name,TUN_DEV,IFNAMSIZ);
if((ioctl_err = ioctl(tun_dev_fd, TUNSETIFF, (void*) &ifr)) < 0)
{
perror("ioctl[TUNSETIFF]");
close(tun_dev_fd);
return ioctl_err;
}
return tun_dev_fd;
}
configuration of this tun0 device:
$sudo ifconfig tun0 10.0.3.4/24 mtu 1500 up
$sudo ip route add default gateway via 10.0.3.10 dev tun0
$sudo iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
and ping response now:
ping 8.8.8.8 -I tun0
ping: Warning: source address might be selected on device other than tun0.
PING 8.8.8.8 (8.8.8.8) from 10.0.2.15 tun0: 56(84) bytes of data.
^C
--- 8.8.8.8 ping statistics ---
20 packets transmitted, 0 received, 100% packet loss, time 1028ms
Any help would be appreciated...
Standard network interfaces have a piece of hardware behind them (a network card).
Tuntap don't:
https://www.kernel.org/doc/Documentation/networking/tuntap.txt
tl;dr: packets sent to a tuntap interface are handed over to a user-space program for processing. This program takes on the role of the network card in some way (example: openvpn). Unless there is a program taking packets out of the device and doing something meaningful with them, they will vanish into the void (like a network card with a disconnected cable).

Can I just run one port to send packet continuously in Pktgen?

I want to accomplish to send packet continuously in port "0",and I have done some configuraition:
./app/x86_64-native-linuxapp-gcc/pktgen -l 0-2 -n 4 --proc-type auto --socket-mem 1024 -b 00:08.0 -- -P -m "[1].0"
and in the interactive CLI I set something:
Pktgen>set 0 src ip "192.168.12.2/24"
Pktgen>set 0 dst ip "192.168.12.3"
Pktgen>set 0 proto udp
Pktgen>set 0 count 0
Pktgen>set 0 rate 50
Pktgen>set 0 size 64
Pktgen>start 0
But according to the page main display, the port 0 just transmit few packets and stop to send packet anymore,even I stop 0 and start 0 again, there is no any response.
Pktgen must config two dpdk ports? when I config two dpdk ports and run scripts/rfc2544_tput_test.lua, it works well,I want to know why...
Yes, you can. It work seamlessly. Only requirement, the other side should be able to detect link state change.

snmptrapd logging error- couldn't open udp:162 -- errno 98 ("Address already in use")

I am trying to receive a trap generated by a cisco router on my VM- Ubuntu 14.04. I can do a snmwalk so I guess snmp is working fine but I am not able to receive the traps generated by router on my VM.
a#ubuntu:~$ sudo /etc/init.d/snmpd restart
* Restarting network management services:
a#ubuntu:~$ sudo /etc/init.d/snmpd status
* snmpd is running
* snmptrapd is running
Here is what I have inside files-
/etc/default/snmpd-
export MIBS=
SNMPDRUN=yes
SNMPDOPTS='-Lsd -Lf /dev/null -u snmp -I -smux -p /var/run/snmpd.pid -c /etc/snmp/snmpd.conf'
TRAPDRUN=yes
# snmptrapd options (use syslog).
TRAPDOPTS='-n -On -t -Lsd -p /var/run/snmptrapd.pid'
/etc/snmp/-
snmpd.conf-
rocommunity public
snmptrapd.conf-
disableAuthorization yes
snmp.conf-
mibs:
The command I am running for viewing the traps on VM-
a#ubuntu:/etc/snmp$ sudo snmptrapd -f -Lo -c snmptrapd.conf
couldn't open udp:162 -- errno 98 ("Address already in use")
I am confused since the port is being used by snmptrap itself-
a#ubuntu:~$ cat /etc/services|grep 162
snmp-trap 162/tcp snmptrap # Traps for SNMP
snmp-trap 162/udp snmptrap
a#ubuntu:~$ sudo netstat -lnp| grep 162
udp 0 0 0.0.0.0:162 0.0.0.0:* 6216/snmptrapd
a#ubuntu:~$ ps -ef | grep snmptrapd
root 6216 2076 0 10:43 ? 00:00:00 /usr/sbin/snmptrapd -Lsd -p /var/run/snmptrapd.pid
a 6493 2667 0 11:47 pts/8 00:00:00 grep --color=auto snmptrapd
Generating a trap from windows using SnmpTrapGen.exe leads to the same error.
Is there any way of solving this issue? I have googled a lot and stuck on this for days, any help will be very much appreciated.
Thanks a lot in advance!!
Port 162 can listen only with an application. If you get this error , you have an app already running which listens port 162 , those can be snmptrapd service or your own application for snmp traps. You should close one of the applications.

How to bind() on all ports?

I want to use a socket with as port, any port available. But I don't really know how to do it
Here's what I tried :
s_in.sin_family = AF_INET;
s_in.sin_port = htons(0);
s_in.sin_addr.s_addr = INADDR_ANY;
Any idea ?
AFAIK, you can't. One solution is to use port translation. If you're using Linux you can do something such as:
iptables -t nat -A PREROUTING -d 128.66.0.1/32 -p tcp -m tcp --dport 22 -j ACCEPT
iptables -t nat -A PREROUTING -d 128.66.0.1/32 -p tcp -m tcp --dport 1:65535 -j DNAT --to-destination 128.66.0.1:11944
This will map all ports except (except port 22) to port 11944. Then you only have to bind to port 11944 in your program.
It depends what you're trying to do. If you wish to receive data, you must bind a socket to a port. That's the purpose of ports. You can set up a "raw socket", but that means you then have to handle the transport layer headers yourself: you can't just forget about them.
If you just wish to send a UDP datagram, you can sendto without prior bind. Any available port will be used as the source.
If you're looking to take any port available, you may just loop from 1024 to 65355, trying to bind your socket on the first available.
If you want to capture EVERY PORT, what you're looking for is a RAW SOCKET.
More info here : https://en.wikipedia.org/wiki/Raw_socket
And here for linux : http://linux.die.net/man/7/raw

Resources