# Writing divert sockets



## blazerguns (Feb 28, 2013)

Hi All,

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 re-inject 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);
```
sendto(2) 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 what's 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 that's the case, won't my packet get dropped because it has source 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


----------

