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