destination unreachables with raw sockets and a bind

From: Matthew Luckie (kluckie@ihug.co.nz)
Date: Mon Nov 18 2002 - 20:48:09 EST


Hi

if you open an ICMP raw socket and then bind to an address (like you do
with the -S option to BSD ping or -I to linux ping) it appears that you
do not get ICMP unreachables if any are sent to you.

compare the call to __raw_v4_lookup in icmp.c icmp_unreach() to that in
raw.c raw_v4_input() to see what i mean.

i've included test code (unreach_send.c, unreach_listen.c) so that you
can test it yourself, and a patch that fixes the kernel. the send needs
to be run on a seperate machine to trigger the address comparison error.

patch is against linux-2.4.19

-- 
Matthew Luckie
kluckie@ihug.co.nz

--- icmp.c.orig Tue Nov 19 13:10:30 2002 +++ icmp.c Tue Nov 19 13:24:53 2002 @@ -16,6 +16,8 @@ * Other than that this module is a complete rewrite. * * Fixes: + * Matthew Luckie : fix call to __raw_v4_lookup in + * icmp_unreach * Clemens Fruhwirth : introduce global icmp rate limiting * with icmp type masking ability instead * of broken per type icmp timeouts. @@ -649,8 +651,8 @@ read_lock(&raw_v4_lock); if ((raw_sk = raw_v4_htable[hash]) != NULL) { - while ((raw_sk = __raw_v4_lookup(raw_sk, protocol, iph->daddr, - iph->saddr, skb->dev->ifindex)) != NULL) { + while ((raw_sk = __raw_v4_lookup(raw_sk, protocol, iph->saddr, + iph->daddr, skb->dev->ifindex)) != NULL) { raw_err(raw_sk, skb, info); raw_sk = raw_sk->next; iph = (struct iphdr *)skb->data;

#include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <sys/unistd.h> #include <netinet/in.h> #include <errno.h>

int main(int argc, char *argv[]) { fd_set rfds; int nfds; int bound; int unbound; struct sockaddr_in sin; char *bind_addr = "192.168.1.1"; u_char buf[2048]; size_t bufsize; socklen_t len;

bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; inet_pton(AF_INET, bind_addr, &sin.sin_addr);

bound = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); unbound = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

if(bound == -1 || unbound == -1) { printf("could not open sockets\n"); return -1; }

if(bind(bound, (struct sockaddr *)&sin, sizeof(sin)) == -1) { printf("could not bind to %s, errno %d\n", bind_addr, errno); return -1; }

while(1) { FD_ZERO(&rfds);

FD_SET(bound, &rfds); FD_SET(unbound, &rfds);

if(bound < unbound) nfds = unbound; else nfds = bound;

if(select(nfds+1, &rfds, NULL, NULL, NULL) < 1) { return -1; }

if(FD_ISSET(bound, &rfds)) { printf("got something on the bound socket\n"); recvfrom(bound, buf, bufsize, 0, (struct sockaddr *)&sin, &len); }

if(FD_ISSET(unbound, &rfds)) { printf("got something on the unbound socket\n"); recvfrom(unbound, buf, bufsize, 0, (struct sockaddr *)&sin, &len); } }

return 0; }

#include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <sys/unistd.h> #include <netinet/in.h> #include <errno.h>

#define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ #define ICMP_HOST_UNREACH 1 /* Host Unreachable */

struct icmphdr { u_int8_t type; u_int8_t code; u_int16_t checksum; u_int16_t id; u_int16_t sequence; };

int main(int argc, char *argv[]) { fd_set rfds; int nfds; int sock; struct sockaddr_in sin; char *dest_addr = "192.168.1.1"; u_char buf[sizeof(struct icmphdr)]; size_t bufsize; struct icmphdr *icmp; socklen_t sa_len = sizeof(struct sockaddr_in); int len = sizeof(buf);

bzero(&sin, sizeof(sin)); inet_pton(AF_INET, dest_addr, &sin.sin_addr); sin.sin_family = AF_INET;

sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if(sock == -1) { printf("could not open socket: errno %d\n", errno); return -1; }

icmp = (struct icmphdr *)buf; bzero(buf, sizeof(buf)); icmp->type = ICMP_DEST_UNREACH; icmp->code = ICMP_HOST_UNREACH; icmp->checksum = 0;

if(sendto(sock, buf, len, 0, (struct sockaddr *)&sin, sa_len) == -1) { printf("could not sendto, errno %d\n", errno); return -1; }

return 0; }

- To unsubscribe from this list: send the line "unsubscribe linux-net" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html



This archive was generated by hypermail 2b29 : Sat Nov 23 2002 - 22:00:00 EST