2.4.0 and sendmsg problem. Maybe NAT bug.
Gleb Natapov
gleb@nbase.co.il
Thu, 20 Jul 2000 14:55:46 +0000
This is a multi-part message in MIME format.
--------------9A80E68ECB7B543C4C3FFDAA
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hello,
I have reported this problem to linux-net but haven't received any
response yet. I think that the better place for this bug report is this
mail list because it seem that the problem is in the NAT code.
Problem:
I have a computer with two network interfaces: eth0 - 10.0.1.1/24
eth1 - 10.0.2.1/24
I wrote a small program (attached) that gets two parameters
interface name ('if') and destination address ('dst'). The program sends
ip
packets to address 'dst' via interface 'if'.
If I run the program in kernel 2.2.x as follows:
# ./sendmsg_test eth1 10.0.1.2
I can see in tcpdump that linux tries to send packets via interface
eth1. It actually sends arp requests for address 10.0.1.2 and never gets
the answer since this host is only reachable via another interface, but
if I add arp entry from command line (arp -i eth1 -s 10.0.1.2 mac_addr)
I see that packets are sent via interface eth1.
If I run the same command in kernel 2.4.0-testX I see that linux sends
packets via eth0 and not eth1 as one would expect. The source address of
the packets is the address of eth0.
I have netfilter and NAT compiled in but I haven't setup any custom
rules.
I think that the problem is in 'do_extra_mangle()' function
(ip_nat_core.c).
This function calls 'ip_route_output()' for dst (in my case 10.0.1.2),
finds route to the destination via eth0 , replaces source address of the
packet with address of eth0, skb is marked as NFC_ALTERED,
'output_maybe_reroute()' checks this flag and reroute packet via eth0
interface.
I don't know wy we need 'do_extra_mangle()' at all (I am not familiar
with NAT code), but it seems that we shouldn't call 'ip_route_output()'
blindly for each locally generated packet there.
If I comment whole 'do_extra_mangle()' function my program works as
expected.
PS: I am not subscribed to the list, add my e-mail to cc on reply
please.
--
Gleb.
--------------9A80E68ECB7B543C4C3FFDAA
Content-Type: text/plain; charset=us-ascii;
name="sendmsg_test.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="sendmsg_test.c"
#include <errno.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <strings.h>
#include <stdio.h>
struct in_pktinfo
{
int ipi_ifindex; /* Interface index */
struct in_addr ipi_spec_dst; /* Routing destination address */
struct in_addr ipi_addr; /* Header destination address */
};
int main(int argc, char **argv)
{
int fd;
struct sockaddr_in sa;
static struct msghdr m;
struct ifreq ifr;
char buffer[10]={'6',};
struct iovec iov = {buffer, 0};
struct {
struct cmsghdr cm;
struct in_pktinfo ipi;
} cmsg = { {sizeof(struct cmsghdr) + sizeof(struct in_pktinfo),
SOL_IP, IP_PKTINFO}, {0, }};
if (argc < 3)
exit(1);
fd = socket (PF_INET, SOCK_RAW, IPPROTO_UDP);
if (fd < 0) {
perror ("socket:");
exit(1);
}
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, argv[1], 15);
if(ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
fprintf(stderr, "unknown iface %s\n", argv[1]);
exit(1);
}
cmsg.ipi.ipi_ifindex = ifr.ifr_ifindex;
sa.sin_family = AF_INET;
sa.sin_port = htons(0);
sa.sin_addr.s_addr = inet_addr(argv[2]);
iov.iov_len = 10;
m.msg_name = &sa;
m.msg_namelen = sizeof(sa);
m.msg_iov = &iov;
m.msg_iovlen = 1;
m.msg_control = &cmsg;
m.msg_controllen = sizeof(cmsg);
m.msg_flags = 0;
while (1){
sleep(1);
sendmsg(fd, &m, 0);
}
}
--------------9A80E68ECB7B543C4C3FFDAA--