View on
Stephanie Wehner > Net-Divert-0.01 > Net::Divert



Annotate this POD

View/Report Bugs
Module Version: 0.01   Source  


Net::Divert - Divert socket module


  use Net::Divert;


The Net::Divert module facilitates the use of divert sockets for packet alteration on FreeBSD and MacOSX.

Divert sockets can be bound to a certain port. This port will then receive all packets you divert to it with the help of a divert filter rule. On FreeBSD and MacOSX ipfw allows you to add such a rule. Please refer to the divert and ipfw manpages for more information.

This module allows you to create a divert socket and then just supply a function that will deal with the incoming packets.

new(host,port) will create a new divert object. It will also create a divert socket bound to the specified port at the given host/ip.

getPackets(func) will create a loop getting all incoming packets and pass them onto the specified function you created. This function will be called with two arguments: packet and fwtag. Fwtag contains the rule number where the packet is reinserted. Refer to divert(4) for more information.

putPacket(packet,fwtag) reinsert a packet at the specified fw rule (normally you don't want to alter fwtag, as it is easy to create infinite loops this way)


First of all, you need a ipfw divert rule, for example: ipfw add divert 9999 all from any to 80

Basic framework:

use Net::Divert;

$divobj = Net::Divert->new('yourhostname',9999);


sub alterPacket { my($packet,$fwtag) = @_;

    # here you can do things to the packet

    # write it back out


You can modify the header of the packet as well as its payload. Say you wanted to turn on the tcp ece and cwr flags in all tcp packets:

use Net::Divert; use NetPacket::IP; use NetPacket::TCP;

$divobj = Net::Divert->new('yourhostname',9999);


sub alterPacket { my($packet,$fwtag) = @_;

    # decode the IP header
    $ip_obj = NetPacket::IP->decode($packet);

    # check if this is a TCP packet
    if($ip_obj->{proto} == IP_PROTO_TCP) {

        # decode the TCP header
        $tcp_obj = NetPacket::TCP->decode($ip_obj->{data});

        # set the ece and cwr flags
        $tcp_obj->{flags} |= ECE | CWR;

        # construct the new ip packet
        $ip_obj->{data} = $tcp_obj->encode($ip_obj);
        $packet = $ip_obj->encode;


    # write it back out

When you alter the payload of an IP packet, the total length in the IP header will be adjusted automatically when the packet is reencoded.


Altering the payload in TCP packets does not work this easily. You can modify the payload in such a way that the length of the payload stays the same. If you just want to modify, say, an outgoing webrequest you can also make the payload smaller. The problem is inherent in the way TCP uses sequence numbers. Data flowing from one host to the other is a stream of data, spread out over multiple packets. The sequence number identifies the byte in this stream of data from the sender to the receiver that the first byte in this segment represents. If you change the size of a packet in between the state on both ends will be disynchronized. See TCP/IP Illustrated Vol. 1 for more information on TCP.

You need at least NetPacket 0.03 to do the modifications described above.


Packet modifications are done on packet per packet basis. If you would want to make modifications spanning multiple packets, you would have to keep packets in a alterPacket yourself. Keep in mind though that because of retransmissions on the sending side, this might not be possible for too long.


Stephanie Wehner,


Copyright (c) 2001 Stephanie Wehner. All rights reserved. This module is released under the BSD License. See the file LICENSE for details.


perl(1), divert(4), ipfw(8)

syntax highlighting: