Shlomi Fish avatar Shlomi Fish committed 3367aca

First BerliOS release

Comments (0)

Files changed (38)

ip-noise/ip-noise/Docs/Arbitrator_Architecutre.txt

+The Arbitrator is going to have two threads:
+
+1. The Arbitrating Thread - this thread accepts packets from the
+Packets Queue, decides what to with them according to the Markovian chains
+and if it is to be delayed, it puts it in the priority queue of the release 
+thread (which is not part of the arbitrator and is described in 
+Architecure.txt.
+
+2. The Chains States Maintainance thread - this thread updates the
+active states of the Markovian chains by using a priority queue.
+
+It is possible that there will be several arbitrating threads, all of which
+are symetrical. Each one will decide what to do with a single packet before
+opting to receive others of its kind.
+
+The chains states maintainance thread is quite trivial to write. Therefore,
+most of this document will focus on the Arbitrating Thread.
+
+Chain Filter Structure:
+-----------------------
+
+A chain filter structure will look as follows:
+
+struct chain_filter
+{
+    ip_specification * source;
+    ip_specification * dest;
+    int protocols; /* A bit mask specifiying which protocols to filter */
+    int tos_precedence; /* A bit mask for the various precendence available */
+    int tos_bits; /* Bit masks for the acceptibility of Delay, Throughput and
+                     Relay-ability. Bits:
+                        0 - If set no-delay is accepted.
+                        1 - If set delay is accepted
+                        2 - If set no-throughput is accepted.
+                        3 - If set throughput is accepted
+                        4 - If set no-Relayability is accepted
+                        5 - If set Relayibility is accepted.
+
+                  */
+    int min_packet_len;
+    int max_packet_len;
+    int which_packet_len; /* 
+                             Can be - 0 - don't care.
+                             1 - Greater than min 
+                             2 - Lower than max
+                             3 - Between min and max
+                             4 - Not between min and max.
+                          */
+}
+
+And the ip_specification struct is defined as follows:
+
+struct ip_specification
+{
+    ip_specification * next; /* = NULL to terminate the linked list. */
+
+    bit inverse; /* Inverse the condition */
+    in_addr ip;
+    int net_mask; /* The sub-net width of the IP range */
+    int num_port_ranges; /* If = 0 then any port will do. */
+    /* A sorted array of port ranges. We do a binary search to see
+       if the port of the packet matches them. */
+    port_range_struct * port_ranges; 
+}
+
+State Syntax:
+-------------
+
+struct state_struct
+{
+    probability_type drop_prob;
+    probability_type delay_prob;
+    delay_type * delay_function;
+    int time_factor;
+    int num_move_tos;
+    move_to_type * move_tos;
+    probability_type stable_delay_prob;
+}
+
+struct move_to_type
+{
+    probabilty_type comulative_prob;
+    int which_state; /* Determines the state to go to */
+}
+
+Move to is a sorted array. We search it for the apropriate probability
+in the range (0,1) and from that we determine the state to go to next.
+
+Chain Syntax:
+-------------
+
+struct chain_struct
+{
+    int num_states;
+    state_type * states;
+
+    int current_state;
+    chain_filter_type * filter;
+
+    time_t time_of_last_packet;
+
+    Dictionary <String -> Int> state_names;
+}
+
+Arbitrator Data Structure Syntax:
+---------------------------------
+
+struct arbitrator_struct
+{
+    int num_chains;
+    chain_type * chains;
+
+    read_write_lock_t lock;
+
+    priority_queue<change_state_event_type> change_states_pq;
+
+#if there is more than one arbitrator threads:
+    mutex protect_num_active_threads;
+    int num_active_threads;
+    bool terminate_threads;
+#endif
+
+    Dictionary <sting -> int> chain_names;
+}
+
+struct change_state_event_struct
+{
+    int chain;
+    time_t invalidation_time;
+}
+
+
+The Delay Function Type:
+------------------------
+
+struct delay_function_struct
+{
+    int type;
+                 
+    union params
+    {
+        double lambda;
+        struct split_linear_function_struct
+        {
+            int num_points;
+            struct prob_and_delay 
+            {
+                probability_t prob;
+                double delay;
+            } * points;
+        };
+    };
+}

ip-noise/ip-noise/Docs/Architecture.txt

+Msg:
+----
+
+The class Msg is an implementation of a "Heap" element that contains
+the actual IP packet as well as the time (in seconds and microseconds)
+of its arrival. 
+
+There's nothing too interesting there, and the functions are very short
+and trivial. For more information consult the Heap::Elem man page.
+
+Delayer:
+--------
+
+Delayer is a class that handles delaying packets with the possibility
+of different delay lengths and different arrival times. It accepts 
+the packets as is and does not decide how much to delay them itself.
+Moreover, it does not use the IP-Queue interface directly and rather
+uses a callback to release the packets after their delay.
+
+This module has two methods:
+
+delay_packet() - this method accepts a packet, its arrival time
+and the amount of time, in quanta of 1 millisecond, to delay it, 
+and register this packet to be released only at this amount of time 
+at the future.
+
+release_packets_poll_function() - this method should be called periodically
+in order to release those packets whose time has come to be released.
+
+The class uses a priority queue to organize the packets and their release
+times. release_packets_poll_function() constantly peaks the minimal item of 
+the PQ to determine whether its release time has already come. If so, 
+it extracts it out of there.
+
+Packet::Logic:
+--------------
+
+Perhaps should have been named "Packet::Arbitrator" or "Packet::Decide".
+This class determines what to do with a packet. It has one method -
+decide_what_to_do_with_packet() which returns the outcome of the packet.
+This way, a state can be implemented inside the object.
+
+The function should return a reference to a hash that contains the following 
+fields:
+
+'action' - can be of value "accept", "delay", or "drop".
+'delay_len' => applicable only if 'action' is "delay". This is the delay
+in quanta.
+
+At the moment this function implements a simple state-less rule-based noise
+, where the rules are not unlike the IP firewalling rules of the kernel. A
+better description of the format of the rules should be written at a
+certain stage, but is not available now.
+
+main.pl:
+--------
+
+This is a script that use Delayer, Packet::Logic and the IP-Queue interface. 
+However, it can be easily encapsulated in its own class by an experienced
+perl coder.
+
+The script performs a loop in which it:
+1. Gets the next message from the IP-Queue.
+2. Calls release_packets_poll_function to release the appropriately delayed 
+   packets.
+3. Call decide_what_to_do_with_packet() to get its verdict.
+4. Accepts, drops, or queues the packet for delay based on its verdict.
+5. Return to Step #1.
+
+Note that this script relies on a fact that packets constantly arrive 
+at the IP Queue for verification. If not it may get stuck, while some
+packets that need to be released after a significant delay will not be
+released. 
+
+This can be easily solved by putting step #2 on its own thread, but it has
+not been done yet. (Some versions of the perl interpreter do not support 
+multi-threading).
+
+main_mt.pl:
+-----------
+
+This script is similar to main.pl only that it initiates three threads, each
+of which is responsbile for doing one operation:
+
+1. The main thread gets a message from the IP-Queue, stamps it with its
+arrival time and places it inside a (thread-safe) queue.
+
+2. The arbitrator thread gets a message from that queue, and determines what
+to do with it. If it should be dropped or released it does so. If it is to 
+be delayed it invokes the delayer to delay it.
+
+3. The delayed packets' release thread performs an infinite loop in which
+it calls the delayer's release_packets_poll_function() method.
+
+By using this scheme, one can ensure that the delayed packets will be released
+on time, even if the traffic is inconsistent.
+
+    Notes:
+    1. This file requires the perl interpereter to be compiled with 
+       multi-threading support.
+    2. This file contains some duplicate code with main.pl. I'd like to wrap
+       their functionality in a nice object, which can be used by both 
+       the non-threaded script and the threaded script.
+
+

ip-noise/ip-noise/Docs/Protocol.txt

+
+State - If 0 is transmitted - <int32> - index
+        If 1 is transmitted - <string> - its name
+        <string> is string_len+1 bytes that terminate with a NULL character.
+        string_len should be 127 bytes or so.
+
+Chain - If 0 is transmitted - <int32> - index
+        If 1 - <string> - its name
+
+Return Values - 0 - OK
+                1 - Wrong Input
+                
+Packet Range - start=<int16> end=<int16> 
+               If start > end then it's a terminator.
+
+Packet Ranges Specifier - <Packet Range> <Packet Range> .... <Terminator>
+
+IP Component - ip=<int32> 
+               netmask_width=<int32> 
+               inverse=<bool> 
+               <Packet Ranges Specifier>
+
+IP Component Terminator - ip=255.255.255.255 but there is still a netmask
+and a packet range specifier for parity.
+
+IP Filter - <IP Component> <IP Component> <IP Component> <Terminator>
+
+Split Linear Specifier Token : 
+    prob=<Probability Type>
+    delay=<Delay Type>
+
+    terminator (last element) is when prob=1.
+
+Split Linear Specifier:
+    <Split Linear Token> <Split Linear Token> ... <Terminator>
+
+Delay Type - any of:
+    1. Exponential   0x0
+    2. Split Linear  0x1
+    
+
+Protocol Operations:
+
+
+* Define a new chain.
+
+    Input: <0x0000> chain_name=<string>
+    Output : <RetValue> chain_number=<int32>
+
+    Note: even if RetValue indicates failure we still broadcast the
+    chain number, which should be ignored by the front-end.
+
+* Define a new state in a chain.
+
+    Input: <0x0001> chain=<Chain> state_name=<State>
+    Output : <RetValue> state_number=<int32>
+
+* Define the move probabilities between states @source to states @dest.
+(by using a matrix of inputs) inside a chain.
+
+    Input: <0x0002> 
+           chain=<Chain> 
+           scalar(@source)=<int32> 
+           scalar(@dest)=<int32> 
+           $source[0]=<State>
+           $source[1]=<State>
+           .
+           .
+           $dest[0]=<State>
+           $dest[1]=<State>
+           $dest[2]=<State>
+           probs($s -> $d)=<Probability Type> (scalar(@source)*scalar(@dest) of them)
+
+    Return: <RetValue>
+
+* Chain Filters:
+    - Set source to something.
+        Input: <0x0003>
+               chain=<Chain>
+               filter=<IP Packet Filter>
+        Output:
+            <RetValue>
+            
+    
+    
+    - Set dest to something
+        Input: <0x0004>
+               chain=<Chain>
+               filter=<IP Packet Filter>
+        Output:
+            <RetValue>
+        
+    - Enable/Disable Protocol X.
+        Input: <0x0005>
+              chain=<Chain>
+              protocol_id=<int32>
+                - If = 256 then all protocols should be enabled or disabled.
+              enable_or_disable=<bool>
+        Output:
+            <RetValue>
+        
+    - Set TOS Precedence Bits
+        Input: <0x0006>
+               chain=<Chain>
+               Precedence = <int16>
+        Output:
+            <RetValue>
+            
+    - Set TOS bits mask
+        Input: <0x0007>
+            chain=<Chain>
+            tos_bits_mask=<int16>
+        Output:
+            <RetValue>
+
+    - Set Min. packet length
+        Input: <0x0008>
+               chain=<Chain>
+               Min_Packet_Length=<int16>
+        Output:
+            <RetValue>
+            
+    - Set Max. packet length
+        Input: <0x0009>
+               chain=<Chain>
+               Max_Packet_Length=<int16>
+        Output:
+            <RetValue>
+
+    - Set Which packet length
+        Input: <0x000a>
+               chain=<Chain>
+               Which_Packet-Length=<int16>
+        Output:
+            <RetValue>
+                             Can be - 0 - don't care.
+                             1 - Greater than min 
+                             2 - Lower than max
+                             3 - Between min and max
+                             4 - Not between min and max.
+
+* Retrieve the index of the chain (by name).
+        Input: <0x000b>
+            chain=<Chain>
+            
+        Output:
+            <RetValue> 
+            chain#=<int32>
+
+* Retrieve the index of a state within a chain (by name).
+        Input: <0x000c>
+            chain=<Chain>
+        Output:
+            <RetValue> 
+            state_index=<int32>
+
+* Retrieve the move probabilities between @source and @dest.
+        Input: <0x000d>
+               chain=<Chain>
+               scalar(@source)=<int32> 
+               scalar(@dest)=<int32> 
+               $source[0]=<State>
+               $source[1]=<State>
+               .
+               .
+               $dest[0]=<State>
+               $dest[1]=<State>
+               $dest[2]=<State>
+        Output:
+               <RetValue>
+               prob[$s][$d]=<Probability Type> for each source and dest.
+
+* Set the drop/delay prob of a state.
+        Input: <0x000e>
+               chain=<Chain>
+               state=<State>
+               drop_prob=<Probability Type>
+               delay_prob=<Probability Type>
+        Output:
+            <RetValue>
+
+* Set the delay function type of a state.
+        Input: <0x000f>
+               chain=<Chain>
+               state=<State>
+               delay_type=<Delay Type>
+        Output:
+            <RetValue>
+
+* Set the split-linear delay function of a state.
+        Input: <0x0010>
+               chain=<Chain>
+               state=<State>
+               split_linear=<Split Linear Spec>
+        Output:
+            <RetValue>
+               
+
+* Set the delay function's lambda. (in case it is Exponential).
+        Input: <0x0011>
+               chain=<Chain>
+               state=<State>
+               lambda=<lambda_type>
+        Output:
+            <RetValue>
+
+* Set the time factor of a state.
+        Input: <0x00013>
+               chain=<Chain>
+               state=<State>
+               time_factor=<Delay Type>
+        Output:
+            <RetValue>
+               
+
+* Set the stable delay probability of a state. (we mean that packets are sent
+in the order in which they were received).
+        Input: <0x0014>
+               chain=<Chain>
+               state=<State>
+               prob=<Probability Type>
+        Output:
+            <RetValue>
+               
+
+* Delete a state from a chain.
+        Input: <0x0015>
+               chain=<Chain>
+               state=<State>
+        Output:
+            <RetValue>
+
+
+* Delete an entire chain.
+        Input: <0x0016>
+               chain=<Chain>
+        Output:
+               <RetValue>
+
+* Set a chain's current state.
+        Input: <0x0017>
+               chain=<Chain>
+               state=<State>
+        Output:
+               <RetValue>
+
+* Dump all the information of all the chains.
+        Input: <0x0018>
+        Output: 
+            <RetValue>
+            num_chains=<int32>
+            @chains=@<Output_Chain> where 
+                Output_Chain=
+                    name=<string>
+                    current_state=<int32>
+                    time_of_last_packet=<Time Type> where
+                        Time Type=
+                            sec=<int32>
+                            usec=<int32>
+                    filter_protocols=<Bitmask of 32 bytes>
+                    filter_tos_precedence=<int16>
+                    filter_tos_bits=<int16>
+                    filter_min_packet_len=<int16>
+                    filter_max_packet_len=<int16>
+                    filter_which_packet_len=<int16>
+                    filter_source_ip_spec=<IP Specification>
+                    filter_dest_ip_spec=<IP Specification>
+                    states_num=<int32>
+                    @states=@<Output_State> where
+                        Output_State=
+                            drop_prob=<Probability Type>
+                            delay_prob=<Probability Type>
+                            delay_type=<Delay Function Type>
+                            delay_type_param= Depends on delay_type:
+                                If Exponential=
+                                    lambda=<lambda_type>
+                                If Split-linear=
+                                    split_linear_spec=<Split Linear Spec>
+                            time_factor=<Delay Type>
+                            stable_delay_prob=<Probability Type>
+                           
+

ip-noise/ip-noise/Docs/Syntax_Description.txt

+Internals:
+----------
+
+There are going to be several Markovian chains, each one with its
+own rules that decide which packets to pass to it. It is possible 
+that a packet would be processed in more than one chain. In this
+case:
+
+1. If one of those chains decided to drop it - the packet would be dropped.
+2. Else, the packet would be delayed for a sum of the delays of the chains.
+
+Each chain will store the time of the last packet that was sent. There is 
+a probability constant in each of its states that determines if the delay 
+is relative to the time of the last packet, or an absolute delay. 
+
+Each one of a chain's states contains the probabilities of the releasing,
+dropping or delaying a packet, as well as the delay function (refer to "Delay
+Functions"). It also contains the probabilities of passing to the other states.
+
+There should always be one special chain called the default chain, which
+determines what to do with packets that did not fit into any other chain, 
+assuming that they indeed did not.
+
+Chain Filters:
+--------------
+
+A chain filter may refer to the following specifications:
+
+Source IP Address: a list of subnets, each specified in a similar way
+to that of the Linux fire-walling rules. Each IP or subnet is accompanied
+with a specification of the input port (if appropriate to the protocol).
+
+Examples:
+
+{ 129.28.5.0/24:80,8080-8090 ; 132.68.0.0/16:20-21 }
+
+; - separates IP/Masks/Ports constructs
+, - separate ports
+/ - separate the number of 1's in the net-mask from the IP address.
+
+Destination IP Address: Same syntax as the source IP Address.
+
+Protocol : can be a list of any of TCP, udp, icmp or any other of
+the /etc/protocols protocols, or an inversion of such list.
+
+Type of Service:
+
+    Is split into several specifications:
+    Precedence: can be any of the 3-bit octets.
+    Delay            \
+    Throughput       |- Each a one-bit flag.
+    Relay-ability     /
+
+    Each one of those fields may be safely specified to be ignored.
+
+Packet Length:
+
+    Can be "l>5000", "l<3000", "200<l<600".
+
+Whole Chains Syntax:
+--------------------
+
+State "A" {
+   drop = 0.2
+   delay = 0.1
+   delay_type = [!--- A Delay Function ---]
+   time_factor = 500 # This is the time factor to move to the other state
+   move_to = {
+        0.2 = B
+        0.3 = C
+        0.5 = E
+   }    
+}
+
+Chain "MyChain" {
+    source = ...   #  All of these are optional
+    dest =  ...    #
+    length =       #
+    protocol =     #
+    ToS/QoS =      #
+    
+    State "A" { 
+        ...
+    }
+    State "B" { 
+        ...
+    }
+}
+
+Chain "default" {
+
+}
+
+The identifiers are case-insensitive
+
+Delay Functions:
+----------------
+
+1. Exponential: With a given Lambda     E(500)
+
+2. Uniform : From t=t_{start} to t=t_{end} U(500,1500)
+
+3. Generic: Define a function from [0,1] using intermediate points. Between
+two points there is a linear interpolation of them. ( a la Spice)
+
+Generic {
+    0 = 500
+    0.1 = 500
+    0.2 = 300
+    0.5 = 0
+    0.8 = 0
+    0.8001 = 1000
+    1      = 2000
+}
+
+Incremental Changes:
+--------------------
+
+It would be possible to modify the arbitrator at run time. 
+
+Thus, a protocol should be defined so that such incremental changes would 
+be possible.
+
+Examples: 
+
+1. Set move_to of State "A" of Chain "MyChain" to { 0.2 = B, 0.3 = D, 0.5 =A }
+
+2. Set time_factor of State "A" of Chain "MyChain" to 900.
+
+3. Define new Chain "Hello" as { }.
+
+4. Delete chain "MyChain".
+
+5. Override chain "Hello" as { }.
+
+6. Define new state "MyState" in Chain "Hello" as { }
+
+7. Define in chain "Hello" probabilities of transfer from (A,B,C,D) to 
+(A,B,C,D,E,time_factor) as { ... matrix ... }.
+
+
Add a comment to this file

ip-noise/ip-noise/Docs/ip_noise.spec.zip

Binary file added.

ip-noise/ip-noise/perl/arbitrary_delay/IP-Noise-Engine-perl/ChangeLog

+Version 0.1.3:
+--------------
+
+* Initiated threads for the thread functions of main_mt.pl
+
+* Placed the packet arbitrator under its own thread.
+
+* Made sure that the packet arrival time will be decided at the main 
+script.
+
+Version 0.1.2
+-------------
+
+* First release to be documented in this change log.
+
+* Msg class, Delayer class, Packet::Logic class. 
+
+* Packet::Logic contains a simple, incomplete, state-less, 
+rule-based arbitrating system.
+

ip-noise/ip-noise/perl/arbitrary_delay/IP-Noise-Engine-perl/Delayer.pm

+package Delayer;
+
+use strict;
+
+use Heap::Binary;
+use Time::HiRes qw(gettimeofday);
+
+use Msg;
+
+# Our quantom in microseconds
+my $quantom = 1000;
+
+sub new
+{
+    my $class = shift;
+    my $self = {};
+
+    bless $self, $class;
+
+    $self->initialize(@_);
+
+    return $self;
+}
+
+sub initialize
+{
+    my $self = shift;
+
+    # This is a callback to be called for every packet that outght to be 
+    # released.
+    #
+    # Since Perl supports closures it accepts only the packet as a parameter.
+    # When doing it in C, this callback should accept a context variable, that
+    # will be stored in the delayer.
+    my $release_callback = shift;
+
+    $self->{'heap'} = Heap::Binary->new();
+
+    if (ref($release_callback) ne "CODE")
+    {
+        die "One must pass a reference to a subroutine as the release packet" .
+            " callback.\n";
+    }
+
+    $self->{'release_callback'} = $release_callback;
+    
+    return 0;
+}
+
+sub delay_packet
+{
+    my $self = shift;
+
+    my $packet = shift;
+    my $sec = shift;
+    my $usec = shift;
+    my $packet_index = shift;
+
+    my $delay_by = shift;
+
+    # Check if delay_by is only composed of digits
+    if ($delay_by !~ /^\d+$/)
+    {
+        die "\$delay_by must be a positive number!\n";
+    }
+
+    my $delay_to_usec = $usec + $quantom * $delay_by;
+    my $delay_to_sec = $sec;
+    
+    # If delay_to_usec overflows, move the division to sec.
+    if ($delay_to_usec > 1000000)
+    {
+        $delay_to_sec += int($delay_to_usec / 1000000);
+        $delay_to_usec %= 1000000;
+    }
+    
+    my $heap_elem = 
+        Msg->new(
+            $packet, 
+            $delay_to_sec, 
+            $delay_to_usec, 
+            $packet_index
+            );
+    
+    $self->{'heap'}->add($heap_elem);
+
+    return 0;
+}
+
+sub release_packets_poll_function
+{
+    my $self = shift;
+
+    my $release_func = $self->{'release_callback'};
+
+    my $heap = $self->{'heap'};
+
+    my ($sec, $usec) = gettimeofday();
+
+    my $current_time_pseudo_msg = 
+        { 
+            'sec' => $sec, 
+            'usec' => $usec , 
+            'packet_index' => -1, 
+        };
+
+    my $msg;
+
+    # As long as the PQueue is not empty
+    while ($msg = $heap->minimum())
+    {
+        # See if the message should have been sent by now.
+        if ($msg->cmp($current_time_pseudo_msg) < 0)
+        {
+            $release_func->( $msg->get_msg() );
+            $heap->extract_minimum();
+        }
+        else
+        {
+            last;
+        }
+    }
+
+    return 0;
+}
+
+1;
+
+

ip-noise/ip-noise/perl/arbitrary_delay/IP-Noise-Engine-perl/Msg.pm

+package Msg;
+
+use strict;
+
+use vars qw(@ISA);
+
+use Heap::Elem;
+
+@ISA = qw(Heap::Elem);
+
+sub new
+{
+    my $self = shift;
+    my $class = ref($self) || $self;
+
+    #$self = SUPER::new($class);
+    $self = {};
+    bless $self, $class;
+
+    $self->initialize(@_);
+
+    return $self;
+}
+
+sub initialize
+{
+    my $self = shift;
+
+    @{$self}{'msg', 'sec', 'usec', 'index'} = @_;
+
+    $self->{'heap_val'} = 0;
+
+    return 0;
+}
+
+sub cmp
+{
+    my $self = shift;
+    my $other = shift;
+
+    return (($self->{'sec'} <=> $other->{'sec'}) ||
+            ($self->{'usec'} <=> $other->{'usec'}) ||
+            ($self->{'index'} <=> $other->{'index'}) );
+}
+
+sub get_msg
+{
+    my $self = shift;
+
+    return $self->{'msg'};
+}
+
+
+sub heap
+{
+    my $self = shift;
+
+    my $prev_value = $self->{'heap_val'};
+    if (scalar(@_))
+    {        
+        $self->{'heap_val'} = shift;
+    }
+
+    return $prev_value;
+}
+1;

ip-noise/ip-noise/perl/arbitrary_delay/IP-Noise-Engine-perl/Packet/Logic.pm

+package Packet::Logic;
+
+use strict;
+
+use IPTables::IPv4::IPQueue qw(:constants);
+use NetPacket::IP;
+use NetPacket::TCP;
+
+sub new
+{
+    my $class = shift;
+    my $self = {};
+
+    bless $self, $class;
+
+    $self->initialize(@_);
+
+    return $self;
+}
+
+# This function parses the file and splits it into sections where
+# each section corresponds to a rule.
+#
+# Each section contains the rule's arguments in an array.
+sub get_rules_args
+{
+    my $filename = shift;
+
+    my (@rules_list, @rule, $line);
+    open I, "<". $filename;
+    @rule = ();
+    while ($line = <I>)
+    {
+        chomp ($line);
+        # Indicates that we should switch to the next rule.
+        if ($line =~ /<new rule>/i)
+        {
+            # If the rule is not empty
+            if (scalar(@rule) > 0)
+            {
+                # Insert into the rule list a fresh copy of rule
+                push @rules_list, [ @rule ];
+            }
+            # Clean rule so we can read the next rule
+            @rule = ();
+            # Read the next rule
+            next;
+        }
+        # If the line is not empty.
+        if ($line =~ /\S/)
+        {
+            push @rule, $line;
+        }
+    }
+    push @rules_list, [@rule];
+    close(I);
+
+    return \@rules_list;
+}
+
+# This function takes _one_ array of a rule's arguments and
+# and structures it as a rule hash.
+#
+# There's some duplicate code inside this function so it may be wise to 
+# modulate it a bit.
+sub rule_args_to_rule
+{
+    my %rule = 
+    (
+        'drop_prob' => 0,
+        'delay_prob' => 0,        
+    );
+
+    my ($arg);
+    my ($start, $end, @components);
+
+    while (scalar(@_))
+    {
+        $arg = shift;
+        if (($arg eq "--source") || ($arg eq "-s"))
+        {
+            $arg = shift;
+
+            # If it's a range, treat it as such.
+            # If not, treat is as a range with one IP.
+            if ($arg =~ /-/)
+            {                
+                @components = split(/ *- */, $arg);
+                $start = $components[0];
+                $end = $components[1];                
+            }
+            else
+            {
+                $start = $end = $arg;
+            }
+
+            $rule{'source'} = { 'start' => $start, 'end' => $end };
+        }
+        elsif (($arg eq "--dest") || ($arg eq "--destination") || ($arg eq "-d"))
+        {
+            $arg = shift;
+
+            # If it's a range, treat it as such.
+            # If not, treat is as a range with one IP.
+            if ($arg =~ /-/)
+            {                
+                @components = split(/ *- */, $arg);
+                $start = $components[0];
+                $end = $components[1];                
+            }
+            else
+            {
+                $start = $end = $arg;
+            }
+
+            $rule{'dest'} = { 'start' => $start, 'end' => $end };
+        }
+        elsif (($arg eq "--drop-probability") || ($arg eq "--drop-prob"))
+        {
+            $arg = shift;
+
+            if (($arg < 0) || ($arg > 1))
+            {
+                die "Drop Probability is out of range!\n";
+            }
+            $rule{'drop_prob'} = $arg;
+        }
+        elsif (($arg eq "--delay-probability") || ($arg eq "--delay-prob"))
+        {
+            $arg = shift;
+
+            if (($arg < 0) || ($arg > 1))
+            {
+                die "Delay Probability is out of range!\n";
+            }
+            $rule{'delay_prob'} = $arg;
+        }
+        elsif ($arg eq "--delay-len")
+        {
+            $arg = shift;
+
+            if ($arg < 0)
+            {
+                die "Delay Length cannot be less than 0!\n";
+            }
+            if ($arg !~ /^\d+$/)
+            {
+                die "Delay length is not an integer!\n";
+            }
+            $rule{'delay_len'} = $arg;
+        }
+    }
+    
+    # TODO: Rule normalization (completing missing arguments)
+
+    if ($rule{'delay_prob'} + $rule{'drop_prob'} > 1)
+    {
+        die "Drop and Delay probabilities evaluate to more than 1!\n";
+    }
+    return \%rule;
+}
+
+sub parse_rules
+{
+    my $filename = shift;
+
+    my @rules_args = @{ get_rules_args($filename) };
+
+    my @rules = (map { &rule_args_to_rule(@{$_}); } @rules_args);
+
+    return \@rules;
+}
+
+sub initialize
+{
+    my $self = shift;
+
+    srand(24);
+
+    $self->{'rules'} = parse_rules("logic.txt");
+
+    return 0;
+}
+
+sub ip_compare
+{
+    my $ip1_str = shift;
+    my $ip2_str = shift;
+    
+    my $result;
+    
+    my @ip1 = split(/\./, $ip1_str);
+    my @ip2 = split(/\./, $ip2_str);
+    
+    for(my $a=0;$a<4;$a++)
+    {
+        $result = ($ip1[$a] <=> $ip2[$a]);
+        if ($result != 0)
+        {
+            return $result;
+        }
+    }
+
+    return 0;
+}
+sub is_in_ip_range
+{
+    my $range = shift;
+    my $ip = shift;
+
+    return ((ip_compare($range->{'start'}, $ip) <= 0) &&
+            (ip_compare($ip, $range->{'end'}) <= 0));
+}
+
+# This method should return
+# $ret == 0 - if the packet should be accepted immidiately
+# $ret  > 0 - if the packet should be delayed by $ret quanta
+# $ret  < 0 - if the packet should be dropped.
+sub decide_what_to_do_with_packet
+{
+    my $self = shift;
+
+    my $msg = shift;
+
+    if ($msg->data_len())
+    {
+        my $payload = $msg->payload();
+
+        my $ip = NetPacket::IP->decode($payload);
+
+        my $tcp = NetPacket::TCP->decode(NetPacket::IP::ip_strip($payload));
+
+        my @rules_list = @{$self->{'rules'}};
+
+        # Scan the rules. For each rule, determine if it applies to this
+        # packet and if so, determine the packet's outcome.
+        foreach my $rule (@rules_list)
+        {
+            if (exists($rule->{'source'}))
+            {
+                if (! is_in_ip_range($rule->{'source'}, $ip->{src_ip}))
+                {
+                    # Skip to the next rule, if the source IP of the packet
+                    # is not in this source range.
+                    next;
+                }               
+            }
+            if (exists($rule->{'dest'}))
+            {
+                if (! is_in_ip_range($rule->{'dest'}, $ip->{dest_ip}))
+                {
+                    # Skip to the next rule, if the destination IP of the 
+                    # packet is not in this source range.                
+                    next;
+                }               
+            }
+
+            # This packet matches the criteria of this rule, so let's determine
+            # what to do with it.
+            my $prob = rand(1);
+
+            if ($prob < $rule->{'drop_prob'})
+            {
+                return { 'action' => "drop" };
+            }
+            # That way drop_prob < prob < drop_prob + delay_prob and so
+            # the test succeeds in a probability of delay prob.
+            elsif ($prob < $rule->{'drop_prob'} + $rule->{'delay_prob'})
+            {
+                # So far, only a uniform delay is supported.
+                my $delay_len = int(rand($rule->{'delay_len'}));
+
+                return 
+                    { 
+                        'action' => "delay", 
+                        'delay_len' => $delay_len
+                    }
+                    ;
+            }
+            else
+            {
+                return { 'action' => "accept" };
+            }           
+        }
+
+        # None of the tests matched this packet, so let's accept it.
+
+        return { 'action' => "accept" };
+    }
+    else
+    {
+        # What should I do with a packet with a data length of 0.
+        # I know - accept it.
+        return { 'action' => "accept" };
+    }
+}
+
+1;
+

ip-noise/ip-noise/perl/arbitrary_delay/IP-Noise-Engine-perl/TODO

+* Convert to C
+
+* A generic class to handle (sec,usec) times
+
+* Add some more beaf to the rules of Packet::Logic.
+
+* Merge the duplicate code of main.pl and main_mt.pl
+
+* Write a description of the rules.

ip-noise/ip-noise/perl/arbitrary_delay/IP-Noise-Engine-perl/docs/Architecture.txt

+Msg:
+----
+
+The class Msg is an implementation of a "Heap" element that contains
+the actual IP packet as well as the time (in seconds and microseconds)
+of its arrival. 
+
+There's nothing too interesting there, and the functions are very short
+and trivial. For more information consult the Heap::Elem man page.
+
+Delayer:
+--------
+
+Delayer is a class that handles delaying packets with the possibility
+of different delay lengths and different arrival times. It accepts 
+the packets as is and does not decide how much to delay them itself.
+Moreover, it does not use the IP-Queue interface directly and rather
+uses a callback to release the packets after their delay.
+
+This module has two methods:
+
+delay_packet() - this method accepts a packet, its arrival time
+and the amount of time, in quanta of 1 millisecond, to delay it, 
+and register this packet to be released only at this amount of time 
+at the future.
+
+release_packets_poll_function() - this method should be called periodically
+in order to release those packets whose time has come to be released.
+
+The class uses a priority queue to organize the packets and their release
+times. release_packets_poll_function() constantly peaks the minimal item of 
+the PQ to determine whether its release time has already come. If so, 
+it extracts it out of there.
+
+Packet::Logic:
+--------------
+
+Perhaps should have been named "Packet::Arbitrator" or "Packet::Decide".
+This class determines what to do with a packet. It has one method -
+decide_what_to_do_with_packet() which returns the outcome of the packet.
+This way, a state can be implemented inside the object.
+
+The function should return a reference to a hash that contains the following 
+fields:
+
+'action' - can be of value "accept", "delay", or "drop".
+'delay_len' => applicable only if 'action' is "delay". This is the delay
+in quanta.
+
+At the moment this function implements a simple state-less rule-based noise
+, where the rules are not unlike the IP firewalling rules of the kernel. A
+better description of the format of the rules should be written at a
+certain stage, but is not available now.
+
+main.pl:
+--------
+
+This is a script that use Delayer, Packet::Logic and the IP-Queue interface. 
+However, it can be easily encapsulated in its own class by an experienced
+perl coder.
+
+The script performs a loop in which it:
+1. Gets the next message from the IP-Queue.
+2. Calls release_packets_poll_function to release the appropriately delayed 
+   packets.
+3. Call decide_what_to_do_with_packet() to get its verdict.
+4. Accepts, drops, or queues the packet for delay based on its verdict.
+5. Return to Step #1.
+
+Note that this script relies on a fact that packets constantly arrive 
+at the IP Queue for verification. If not it may get stuck, while some
+packets that need to be released after a significant delay will not be
+released. 
+
+This can be easily solved by putting step #2 on its own thread, but it has
+not been done yet. (Some versions of the perl interpreter do not support 
+multi-threading).
+
+main_mt.pl:
+-----------
+
+This script is similar to main.pl only that it initiates three threads, each
+of which is responsbile for doing one operation:
+
+1. The main thread gets a message from the IP-Queue, stamps it with its
+arrival time and places it inside a (thread-safe) queue.
+
+2. The arbitrator thread gets a message from that queue, and determines what
+to do with it. If it should be dropped or released it does so. If it is to 
+be delayed it invokes the delayer to delay it.
+
+3. The delayed packets' release thread performs an infinite loop in which
+it calls the delayer's release_packets_poll_function() method.
+
+By using this scheme, one can ensure that the delayed packets will be released
+on time, even if the traffic is inconsistent.
+
+    Notes:
+    1. This file requires the perl interpereter to be compiled with 
+       multi-threading support.
+    2. This file contains some duplicate code with main.pl. I'd like to wrap
+       their functionality in a nice object, which can be used by both 
+       the non-threaded script and the threaded script.
+
+

ip-noise/ip-noise/perl/arbitrary_delay/IP-Noise-Engine-perl/logic.txt

+--source
+132.68.7.4
+--drop-prob
+0.2
+--delay-prob
+0.2
+--delay-len
+1000
+<NEW RULE>
+--source
+132.69.253.254
+--delay-prob
+0.5
+--delay-len
+4000

ip-noise/ip-noise/perl/arbitrary_delay/IP-Noise-Engine-perl/main.pl

+#!/usr/bin/perl
+use strict;
+
+use Packet::Logic;
+use Delayer;
+use IPTables::IPv4::IPQueue qw(:constants);
+use Time::HiRes qw(gettimeofday);
+
+my $packet_logic = Packet::Logic->new();
+
+my $queue = IPTables::IPv4::IPQueue->new(
+    'copy_mode' => IPQ_COPY_PACKET,
+    'copy_range' => 2048
+    );
+
+if (!$queue) 
+{
+    die IPTables::IPv4::IPQueue->errstr();
+}
+
+
+my $release_callback = 
+    sub {
+        my $msg = shift;
+
+        $queue->set_verdict($msg->packet_id, NF_ACCEPT);
+    };
+
+my $delayer = Delayer->new($release_callback);    
+
+my ($last_sec, $last_usec) = (0, 0);
+my $packet_index = 0;
+while (1)
+{
+    my $msg = $queue->get_message();
+    my ($sec, $usec) = gettimeofday();
+
+    # We have to do something so it won't overflow...
+    $packet_index++;     
+
+    if (! $msg)
+    {
+        die IPTables::IPv4::IPQueue->errstr();
+    }
+    
+    $delayer->release_packets_poll_function();
+
+    my $verdict = $packet_logic->decide_what_to_do_with_packet($msg);
+
+    if ($verdict->{'action'} eq "accept")
+    {
+        # Accept immidiately
+        $release_callback->($msg);
+    }
+    elsif ($verdict->{'action'} eq "drop")
+    {
+        # Drop the packet
+        $queue->set_verdict($msg->packet_id, NF_DROP);
+    }
+    elsif ($verdict->{'action'} eq "delay")
+    {
+        # Delay the packet for $verdict quanta
+        $delayer->delay_packet(
+            $msg,
+            $sec,
+            $usec,
+            $packet_index,
+            $verdict->{'delay_len'}
+            );
+    }
+    else
+    {
+        die "Unknown Action!\n";
+    }
+}
+
+

ip-noise/ip-noise/perl/arbitrary_delay/IP-Noise-Engine-perl/main_mt.pl

+#!/usr/bin/perl
+use strict;
+
+use Thread;
+use Thread::Queue;
+
+use IPTables::IPv4::IPQueue qw(:constants);
+use Time::HiRes qw(usleep gettimeofday);
+
+use Packet::Logic;
+use Delayer;
+
+
+my $packet_logic = Packet::Logic->new();
+
+my $queue = IPTables::IPv4::IPQueue->new(
+    'copy_mode' => IPQ_COPY_PACKET,
+    'copy_range' => 2048
+    );
+
+# Thread::Queue is a class for a thread-safe queue.
+my $packets_to_arbitrate_queue = Thread::Queue->new();
+
+if (!$queue) 
+{
+    die IPTables::IPv4::IPQueue->errstr();
+}
+
+
+my $release_callback = 
+    sub {
+        my $msg = shift;
+
+        $queue->set_verdict($msg->packet_id, NF_ACCEPT);
+    };
+
+my $delayer = Delayer->new($release_callback);    
+
+my $terminate = 0;
+
+sub release_packets_thread_func
+{
+    while (! $terminate)
+    {
+        {
+            lock($delayer);
+            $delayer->release_packets_poll_function();
+        }
+        usleep(500);
+    }
+}
+
+sub decide_what_to_do_with_packets_thread_func
+{
+    my ($verdict);
+
+    while (! $terminate)
+    {
+        my $msg_with_time = $packets_to_arbitrate_queue->dequeue();
+
+        my $msg = $msg_with_time->{'msg'};
+        
+        $verdict = $packet_logic->decide_what_to_do_with_packet($msg);
+
+        if ($verdict->{'action'} eq "accept")
+        {
+            # Accept immidiately
+            $release_callback->($msg);
+        }
+        elsif ($verdict->{'action'} eq "drop")
+        {
+            # Drop the packet
+            $queue->set_verdict($msg->packet_id, NF_DROP);
+        }
+        elsif ($verdict->{'action'} eq "delay")
+        {
+            # Delay the packet for $verdict quanta
+            lock($delayer);
+            $delayer->delay_packet(
+                $msg,
+                $msg_with_time->{'sec'},
+                $msg_with_time->{'usec'},
+                $msg_with_time->{'index'},
+                $verdict->{'delay_len'},
+                );
+        }
+        else
+        {
+            $terminate = 1;
+            die "Unknown Action!\n";
+        }
+    }
+}
+
+my $release_packets_thread_handle = Thread->new(\&release_packets_thread_func);
+my $decide_what_to_do_with_packets_thread_handle = Thread->new(\&decide_what_to_do_with_packets_thread_func);
+
+my ($last_sec, $last_usec) = (0, 0);
+my $packet_index = 0;
+while (1)
+{
+    my $msg = $queue->get_message();
+    my ($sec, $usec) = gettimeofday();
+
+    # We have to do something so it won't overflow...
+    $packet_index++;
+
+    if (! $msg)
+    {
+        $terminate = 1;
+        die IPTables::IPv4::IPQueue->errstr();
+    }
+
+    $packets_to_arbitrate_queue->enqueue(
+        {
+            'msg' => $msg,
+            'sec' => $sec,
+            'usec' => $usec,
+            'index' => $packet_index,
+        }
+        );
+    
+
+}
+
+

ip-noise/ip-noise/perl/arbitrary_delay/IP-Noise-Engine-perl/tests/test_delayer.pl

+#!/usr/bin/perl -w
+use strict;
+
+use Delayer;
+
+sub print_message
+{
+    my $message = shift;
+
+    print "$message\n";
+
+    return 0;
+}
+
+my @messages = ('msg1', 1000, 'msg2', 50, 'msg3', 900, 'msg4', 4000, 'msg5', 30);
+my $d = Delayer->new(\&print_message);
+
+while (scalar(@messages))
+{
+    my $msg = shift(@messages);
+    my $delay = shift(@messages);
+    $d->delay_packet($msg, $delay);
+}
+
+while (1)
+{
+    $d->release_packets_poll_function();
+}

ip-noise/ip-noise/perl/arbitrary_delay/IP-Noise-Engine-perl/tests/test_heap.pl

+#!/usr/bin/perl -w
+
+use strict;
+
+use Heap::Binary;
+
+use Msg;
+
+my @my_messages = 
+    (
+        [ qw(message1 900 500)],
+        [ qw(message2 500 300)],
+        [ qw(message3 900 50)],
+        [ qw(message4 1000 6000)],
+        [ qw(message5 200 30)],
+        [ qw(message6 1000 100)],
+        [ qw(message7 20 100)],
+    );
+
+my @ops = qw(a a a a a a e e a e e e e e);
+
+my $pointer = 0;
+
+my $heap = Heap::Binary->new();
+
+foreach my $operation (@ops)
+{
+    if ($operation eq "a")
+    {
+       my $elem = Msg->new( @{$my_messages[$pointer++]} ); 
+       $heap->add($elem);
+    }
+    elsif ($operation eq "e")
+    {
+        my $elem = $heap->minimum();
+        print ($elem->get_msg(), "\n");
+        $heap->extract_minimum();
+    }
+    else
+    {
+        die "Unknown operation $operation!\n";
+    }
+}
+
+

ip-noise/ip-noise/perl/arbitrary_delay/IP-Noise-Engine-perl/tests/test_threads.pl

+use strict;
+
+use Thread;
+
+sub mythread_func
+{
+    while (1)
+    {
+        print "In the thread!\n";
+        sleep 1;
+    }
+}
+
+my $thr = Thread->new(\&mythread_func);
+
+while(1)
+{
+    print "Main thread!\n";
+    sleep 1;
+}

ip-noise/ip-noise/site/wml/.wmlrc

+-D ROOT~.

ip-noise/ip-noise/site/wml/Makefile

+
+D = /var/www/html/ip-noise
+
+IMAGES = $(D)/style.css \
+         $(D)/docs/Arbitrator_Architecutre.txt                \
+         $(D)/docs/ip_noise.spec.zip                          \
+         $(D)/docs/Syntax_Description.txt                     \
+         $(D)/docs/Architecture.txt                           \
+         $(D)/docs/Protocol.txt                               \
+         $(D)/style.css                                       \
+         $(D)/download/IP-Noise-Engine-perl-0.1.4.tar.gz      \
+         $(D)/download/IP-Noise-Engine-perl-0.1.1.tar.gz      \
+         $(D)/download/IP-Noise-perl-filters-0.1.0.tar.gz     \
+         $(D)/download/IP-Noise-Engine-perl-0.1.5.tar.gz      \
+         $(D)/download/IP-Noise-Engine-perl-0.1.0.tar.gz      \
+         $(D)/download/IP-Noise-Engine-perl-0.1.2.tar.gz
+
+
+SUBDIRS = $(D)/download $(D)/docs $(D)/mailing-list
+
+HTMLS = $(D)/index.html $(D)/download/index.html $(D)/links.html \
+	$(D)/docs/index.html $(D)/mailing-list/index.html
+
+all : $(SUBDIRS) $(HTMLS) $(IMAGES)
+
+$(SUBDIRS) :: % : 
+	@if [ ! -e $@ ] ; then \
+		mkdir $@ ; \
+	fi
+	
+
+$(HTMLS) :: /var/www/html/ip-noise/% : %.wml .wmlrc
+	wml $< > $@
+
+$(IMAGES) :: /var/www/html/ip-noise/% : %
+	cp -f $< $@

ip-noise/ip-noise/site/wml/docs/Arbitrator_Architecutre.txt

+The Arbitrator is going to have two threads:
+
+1. The Arbitrating Thread - this thread accepts packets from the
+Packets Queue, decides what to with them according to the Markovian chains
+and if it is to be delayed, it puts it in the priority queue of the release 
+thread (which is not part of the arbitrator and is described in 
+Architecure.txt.
+
+2. The Chains States Maintainance thread - this thread updates the
+active states of the Markovian chains by using a priority queue.
+
+It is possible that there will be several arbitrating threads, all of which
+are symetrical. Each one will decide what to do with a single packet before
+opting to receive others of its kind.
+
+The chains states maintainance thread is quite trivial to write. Therefore,
+most of this document will focus on the Arbitrating Thread.
+
+Chain Filter Structure:
+-----------------------
+
+A chain filter structure will look as follows:
+
+struct chain_filter
+{
+    ip_specification * source;
+    ip_specification * dest;
+    int protocols; /* A bit mask specifiying which protocols to filter */
+    int tos_precedence; /* A bit mask for the various precendence available */
+    int tos_bits; /* Bit masks for the acceptibility of Delay, Throughput and
+                     Relay-ability. Bits:
+                        0 - If set no-delay is accepted.
+                        1 - If set delay is accepted
+                        2 - If set no-throughput is accepted.
+                        3 - If set throughput is accepted
+                        4 - If set no-Relayability is accepted
+                        5 - If set Relayibility is accepted.
+
+                  */
+    int min_packet_len;
+    int max_packet_len;
+    int which_packet_len; /* 
+                             Can be - 0 - don't care.
+                             1 - Greater than min 
+                             2 - Lower than max
+                             3 - Between min and max
+                             4 - Not between min and max.
+                          */
+}
+
+And the ip_specification struct is defined as follows:
+
+struct ip_specification
+{
+    ip_specification * next; /* = NULL to terminate the linked list. */
+
+    bit inverse; /* Inverse the condition */
+    in_addr ip;
+    int net_mask; /* The sub-net width of the IP range */
+    int num_port_ranges; /* If = 0 then any port will do. */
+    /* A sorted array of port ranges. We do a binary search to see
+       if the port of the packet matches them. */
+    port_range_struct * port_ranges; 
+}
+
+State Syntax:
+-------------
+
+struct state_struct
+{
+    probability_type drop_prob;
+    probability_type delay_prob;
+    delay_type * delay_function;
+    int time_factor;
+    int num_move_tos;
+    move_to_type * move_tos;
+    probability_type stable_delay_prob;
+}
+
+struct move_to_type
+{
+    probabilty_type comulative_prob;
+    int which_state; /* Determines the state to go to */
+}
+
+Move to is a sorted array. We search it for the apropriate probability
+in the range (0,1) and from that we determine the state to go to next.
+
+Chain Syntax:
+-------------
+
+struct chain_struct
+{
+    int num_states;
+    state_type * states;
+
+    int current_state;
+    chain_filter_type * filter;
+
+    time_t time_of_last_packet;
+}
+
+Arbitrator Data Structure Syntax:
+---------------------------------
+
+struct arbitrator_struct
+{
+    int num_chains;
+    chain_type * chains;
+
+    read_write_lock_t lock;
+
+    priority_queue<change_state_event_type> change_states_pq;
+
+#if there is more than one arbitrator threads:
+    mutex protect_num_active_threads;
+    int num_active_threads;
+    bool terminate_threads;
+#endif
+}
+
+struct change_state_event_struct
+{
+    int chain;
+    time_t invalidation_time;
+}
+
+
+The Delay Function Type:
+------------------------
+
+struct delay_function_struct
+{
+    int type;
+                 
+    union params
+    {
+        double lambda;
+        struct split_linear_function_struct
+        {
+            int num_points;
+            struct prob_and_delay 
+            {
+                probability_t prob;
+                double delay;
+            } * points;
+        };
+    };
+}

ip-noise/ip-noise/site/wml/docs/Architecture.txt

+Msg:
+----
+
+The class Msg is an implementation of a "Heap" element that contains
+the actual IP packet as well as the time (in seconds and microseconds)
+of its arrival. 
+
+There's nothing too interesting there, and the functions are very short
+and trivial. For more information consult the Heap::Elem man page.
+
+Delayer:
+--------
+
+Delayer is a class that handles delaying packets with the possibility
+of different delay lengths and different arrival times. It accepts 
+the packets as is and does not decide how much to delay them itself.
+Moreover, it does not use the IP-Queue interface directly and rather
+uses a callback to release the packets after their delay.
+
+This module has two methods:
+
+delay_packet() - this method accepts a packet, its arrival time
+and the amount of time, in quanta of 1 millisecond, to delay it, 
+and register this packet to be released only at this amount of time 
+at the future.
+
+release_packets_poll_function() - this method should be called periodically
+in order to release those packets whose time has come to be released.
+
+The class uses a priority queue to organize the packets and their release
+times. release_packets_poll_function() constantly peaks the minimal item of 
+the PQ to determine whether its release time has already come. If so, 
+it extracts it out of there.
+
+Packet::Logic:
+--------------
+
+Perhaps should have been named "Packet::Arbitrator" or "Packet::Decide".
+This class determines what to do with a packet. It has one method -
+decide_what_to_do_with_packet() which returns the outcome of the packet.
+This way, a state can be implemented inside the object.
+
+The function should return a reference to a hash that contains the following 
+fields:
+
+'action' - can be of value "accept", "delay", or "drop".
+'delay_len' => applicable only if 'action' is "delay". This is the delay
+in quanta.
+
+At the moment this function implements a simple state-less rule-based noise
+, where the rules are not unlike the IP firewalling rules of the kernel. A
+better description of the format of the rules should be written at a
+certain stage, but is not available now.