Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 1 Mar 2013 11:44:48 +1100
From:      Varun Chandramohan <cvaruneng04@gmail.com>
To:        freebsd-current@freebsd.org
Subject:   Divert socket issues.
Message-ID:  <CABhDMELFf=0_YHdn0qLwU0a2j_8PYoM-x6zinj3weC6Kxs7kGg@mail.gmail.com>

next in thread | raw e-mail | index | archive | help
Hi All,

I sent this email to net group, unfortunately I got no response. Iam sorry
if that was the wrong group. Trying it again in this group. I wrote a small
program using divert sockets to capture packets using ipfw at outgoing. The
packets that are captured is for application mangling (mostly http headers)
and resent it back to browser. That means I need to reinject it back in
incoming instead of outgoing. I believe this is possible based on what is
said in the man pages.

Man page:

if sendto(2) is used with a destination IP address of INADDR_ANY, then the
packet is treated as if it were outgoing, i.e., destined for a non-local
address.  Otherwise, the packet is assumed to be incoming and full packet
routing is done.

In the latter case, the IP address specified must match the address of some
local interface, or an interface name must be found after the IP address.
 If an interface name is found, that interface will be used and the value
of the IP
address will be ignored (other than the fact that it is not INADDR_ANY).
 This is to indicate on which interface the packet ``arrived.''

According to these instructions, I want my packet In-bound so I set my
local ip address for the sendto data structure using the below code.

ssize_t
divert_get(int sd, struct sockaddr_in *sa, char *pkt_buf, int buflen){
    ssize_t len;
    unsigned int addrlen;

    addrlen = sizeof(*sa);
    len = recvfrom(sd, pkt_buf, buflen, 0,
                   (struct sockaddr *) sa, &addrlen);
    if(len == -1) {
        bps_log(LOG_ERR, "Unable to recieve message from socket", errno);
    }
    return(len);}


/* addr is passed &sa from the above code */
rebuild_header(void *ptr, struct sockaddr_in *addr) {
ssize_t new_len = change_header(ptr);struct ip *ip = (struct ip*)ptr;
/* this is to divert it to input instead of output */
addr->sin_addr.s_addr = ip->ip_src.s_addr;

 /* Recompute checksums */
  ip->ip_len = htons(new_len);

   cal_ip_cksum(ptr);
   cal_tcp_cksum(ptr);

   if(divert_send(sd, addr, ptr, pkt_len) < 0) {
      printf("No data sent from divert socket %d", errno);
    }
}


I expect the packet to now be inbound but my application is not getting the
response sent by me. The possible case could be kernel dropping the packet.
I even set the port number which is the rule I want to match for example, I
have only two rules 1 and 65535. I tried setting port number to 0,1 and
even 65535 but still the kernel drops the packet.

 addr->sin_port = htons(65535);

sento seems to work fine but the packet does not go through. If I re-inject
the packet back in the outgoing path (same place I took the packet) things
seem to work fine. Can someone please tell me whats wrong here? I don't
seem to understand. The man page is not very clear. I looked a bit into
divert code and it seem to call ip_input() for the packet I re-injected. If
thats the case, won't my packet get dropped because it has src address as
my local address (it expects it to be other way around if server has
responded)? Can someone please clarify this? If I have to still do it, do I
need to modify TCP/IP header fields as well?

Regards,

Varun



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CABhDMELFf=0_YHdn0qLwU0a2j_8PYoM-x6zinj3weC6Kxs7kGg>