libnetng : devel release

[email protected] Mon, 16 Aug 2004 18:47:36 +0200
Newsgroups gmane.comp.security.libnet
Message-ID <[email protected]>
Hi all,

You will find here the current devel version of libnetng:

http://www.security-labs.org/ng-081604.tbz2

Attached is the README.ng also available in the distribution.

Currently, it has only be tested on Linux and Mac OS X. Hence, only
these link layers are supported.

Regarding the builders, I am working this week on porting them to the
new internals because I'll be on vacation next week. Currently, only
these are available:

libnet_build_arp.c       
libnet_build_gre.c
libnet_build_ethernet.c  
libnet_build_ip.c  (only IPv4)
libnet_build_udp.c
libnet_build_fddi.c      
libnet_build_payload.c
libnet_build_tcp.c


Porting a builder goes from easy to complicated. Tomorow, I'll focus
on ICMP. 

If some of you want to give me help on that, it will be very much
appreciated.  Just drop me a mail so that several people dont do the
same work.

Comments, suggestions, fix, patches, and so on are very welcomed :)

	Fred Raynal
README.ng (text/plain, 30.1 KB)
	     What's cool & new in libnet next generation

                             Fred Raynal

                       [email protected]
                          [email protected]



http://www.mew.org/~kazu/doc/piprog.html
http://www.whitefang.com/rin/rawfaq.html


Version: 0.1
Date:    


1. Some definitions before starting
===================================
libnet_context (libnet_t): it contains all information about where you
want to write your packets, and your packets themselves. 

libnet_packet (packet_t): is mainly a buffer. Each layer of the packet
you want to build are placed in there.

libnet_pbuf (pbuf_t): is a replacement for libnet_pblock. It describes
a layer (hdr length, checksum lenght, ...), and a pointer to the
buffer describing the packet in the libnet_packet.

                                   
2. Some new features
====================

* Internal structures
  See http://www.security-labs.org?page=libnetng
  This is not fully up-to-date, but main ideas are already there.

* LIBNET_DEBUG
  The library can eitheror not be compiler with this flag. Then, it
  performs much more sanity checks, that are ignored otherwise.  If
  you want to unset this flag, remove it from Makefile.am.common

* pcap mode
  You can now write packets to a pcap file. That has several advantages:
    - you dont need to be root to look at what your packets look like
    - you can create packet with data link layer you dont even own.

  To do so, you just need to call libnet_init() that way:
      libnet_init(LIBNET_PCAP, <filename>, errbuf);

  Thanks to the amazing work made by tcpdump team, I re-use a part of
  their pcap-bpf.h file (renamed as include/dlt/bpf.h).

* packet
  The core data structure of libnet is ... the packet! That sounds
  amazing, isn't ;-) There is now a real structure you can play with
  if you want. All functions are packet oriented, so you can
  manipulate each layer (called pbuf) composing the packet.

* checksums
  - common API for all protocols: libnet_do_checksum()
  - checksums are now computed in real time 
  - full control: you can change that behavior and call
    libnet_update_checksum() so that they are re-computed.

* User level granularity
  Depending on your needs, you can chose to go very deep into the
  structures provided by libnet, or just use the APIs which will hide
  all the sordid C details.

* multiple packets
  The support for multiple packets in included in the current
  structures, no specific needs of whatever.
  The context_queue of 1.1 is deprecated.

* Payload
  The very cool mechanism from the previous version is still in there.
  But, I also add a specific builder payload that let you have full
  control on the data you have at the end of your packet.

* Unified name resolution
  based on getaddrinfo()/getnameinfo(), provide a new name resolution
  API, independant from the protocol (i.e. work on both IPv4 & IPv6). 



TODO / Work in progress

* port builders and link layer functions from 1.1 API

* libnet_intf_t  - > TODO
  Let you manipulate your network device, giving you information about
  it, or letting you change some of its parameters.

* libnet_decoder_t -> work in progress
  A decoder is a way to run through a buffer (considered as a packet)
  and to "decode" the way you want. Depending on the way you decode
  it, you can either just create a packet_t structure initialized with
  that buffer, or create the answer to that packet (reverse decoder,
  work not yet in progress but planned ;-)
 
* Auto-fragmentation -> TODO
  when a TCP/IP packet is greater than the expected MTU, packet is
  fragmented.
  => Hack libnet_link_write()



3. Level of control
===================

What leads me to start these new internals was that I did not had
enough control on the target of libnet: the packet. So, these new
internals are providing new features making the packet the center of
libnet.

The trouble was in fact that for some applications, building and
sending one or two packets was enough. But for others, more control on
the packets was required. 

With the new API, you get several level of control depending on your
needs. 

- Using the functions libnet_build_<proto>()

  This is done for 2 reasons:
    1. being compatible with the former API
    2. giving a quick and easy way to build a single packet.
  With this functions, you dont waste time with internals, you go
  directly to your goal: building a packet!

  Example #3.1:
    l = libnet_init(LIBNET_PCAP, "test.pcap", errbuf);
    udp = libnet_build_udp(...);
    ipv4 = libnet_build_ipv4(...);
    eth = libnet_build_eth(...);
    libnet_write();
    libnet_destroy(l);

  Nothing else ! Everything is hidden and you dont have to care about
  it.

  Under the hood: in fact, the first time you call a function
  libnet_build_<proto>(), it creates a list of packet which will
  contain a single packet (the one you are building).
  However, if you call such a function while there is more than one
  packet in the list, an error is returned.
  Hence, we need another way to create real lists of packets ...

  As you are using the high level, you have no way to get access to
  the packet itself.

- Using the functions libnet_build_pbuf_<proto>()
  
  Now, you go a bit more in the details. That is usually required when
  you need to control exactly what's happen in your packets, or when
  you want to duplicate them.

  Example #3.2: You are Joker (j), and you want to perform a Man in the
  Middle (aka proxy) between Alfred (a) and Batman (b)

    l = libnet_init(LIBNET_RAW4, "eth0", errbuf);
    udp_aj = libnet_build_udp(..., payload, l);
    ipv4_aj = libnet_build_ipv4(ip_j, ip_a..., l);

    pkt_bj = libnet_new_pkt();
    libnet_register_packet(l, pkt);
    udp_bj = libnet_build_pbuf, udp(..., payload, l, pkt_bj);
    ipv4_bj = libnet_build_ipv4(ip_j, ip_b..., l, pkt_bj);
    
    /* send all packets contained in l */
    libnet_write(l);

  This is convenient when you wish to send several packets at the same
  time. There are functions that let you handle a packet in regard of
  a context (l) :
    libnet_register(): register a packet in a context
    libnet_unregister(): removes a packet from a context


  In the example #3.2, there is a problem: how to retrieve the pointer
  on the first packet that has been implicitly built?
  In fact, you cant!
  At this level of control, you should manage the packets by
  yourself. Hence, if you need to keep the pointers on your packets,
  do it yourself ;-)
  But you can still manipulate your pbuf if you saved the ptags (see
  ex bellow).

  Example #3.3: the same as ex #3.2. As we dont care about keeping the
    packets, we register them in the libnet context l.

    l = libnet_init(LIBNET_RAW4, "eth0", errbuf);
    pkt = libnet_new_pkt();
    libnet_register_packet(l, pkt);
    udp_aj = libnet_build_pbuf, udp(..., payload, l, pkt);
    ipv4_aj = libnet_build_ipv4(ip_j, ip_b..., l, pkt);

    pkt = libnet_new_pkt(); /* previous pointer is lost ... but saved
                             * in context so we dont care */
    libnet_register_packet(l, pkt);
    udp_bj = libnet_build_pbuf, udp(..., payload, l, pkt);
    ipv4_bj = libnet_build_ipv4(ip_j, ip_b..., l, pkt);
    
    /* send all packets contained in l */
    libnet_write(l);

  As you can see, here, we have save each pbuf's ptag, so that we can
  change whatever we want in the packet: we dont need to manage each
  packet.

  But at this level, packets are stored as a linked list. This is
  almost ok when you want to send them all at once. But what if you
  want to prepare some packets, just send one, wait for an answer,
  drink a coffee, ...
  I mean, sometimes, lists are not convenient: trees or automates are
  what you need ... but not what I provide ;-)

- Separating packets and context

  In the 2 previous levels, the context was showed as a container for
  some packets. But it is much more than that. That is also the
  structure handling the writing of the packet(s).

  So, you can chose to use libnet context as en empty shell: just
  initialize it so that it knows where to write packets. Then, build
  some packets, organize them the way you want, and then call a
  specific writing functions which writes a single packet, even if he
  does not belong to the context: libnet_write_pkt().

  Example #3.4: 
    l = libnet_init(LIBNET_RAW_ADV, "eth0", errbuf);

    /* create a first packet: here we create each layer, and will
    update only the one we need later  */
    syn = libnet_new_packet(, errbuf);
    syn_ptag = libnet_build_pbuf_tcp(..., SYN, dst_port, ..., l, syn);
    ip_ptag  = libnet_build_pbuf_tcp(..., src, dst, ..., l, syn);

    /* create a second packet */
    rst = libnet_new_packet(, errbuf);
    rst_tcp = libnet_build_pbuf_tcp(..., RST, ..., l, rst, 0);
    rst_ip  = libnet_build_pbuf_tcp(..., src, dst, ..., l, rst, 0);
    
    /* send SYN packet to test remote port */
    do
    {
        syn_ptag = libnet_build_pbuf_tcp(..., SYN, dst_port--, ..., l, syn);
        libnet_write_pkt(l, syn);
        
        /* do some pcap stuff to test whether a SYN|ACK is received */
        if ( (buf = received_synack()) )
        {
            libnet_buf2pkt(buf, buf_len, synack,);
            /* adjust SEQ and ACK in rst_tcp and rst_ip */
            rst_tcp = libnet_build_pbuf_tcp(..., RST, ..., l, rst, rst_tcp);
            rst_ip  = libnet_build_pbuf_tcp(..., src, dst, ..., l, rst, rst_ip);
            
            libnet_write_pkt(l, rst);
        }

    } while (dst_port > 0);

  You have probably noticed that context l is still used here. In case
  of error, l->errbuf contains a message. No other usage is made from
  l here.

  You also have probably noticed you gain a very fine level of control
  on your buffer/packets.


4. Checksums
============

When a protocol needs a checksum, you just have to set it to 0 in its
builder, and it will be magically computed.
There are different kinds of checksums:
  - immediate: those ones can be computed as soon as you build the
    buffer (ex: VRRP, IPv4)
  - delayed: a checksum is delayed when it needs information that are
    not yet in the packet to be computed (ex: TCP/UDP needs IP src and
    dst addresses).
  - optional: some protocols let you decide whether you put a checksum
    or not (ex: GRE)
All this is totally transparent to you, you dont have to handle that
as libnet does it :-)

Conversely, if you want a checksum to be wrong and non 0, just set it
and it will go as you wish in the packet.

* Re-using packets/pbufs  and checksums

The checksum is automatically computed ASAP when you build a packet
for the first time. However, you may sometimes re-use an old packet,
by just changing some data or even a single bit: you need to recompute
the checksums of some headers. This is automatically done before
writing the packet. The update of all the checksums could be done as
soon as you change something in a packet, but that would not be
efficient as you would need to:
  - run through all the pbufs in the packet
  - check if they need to recompute their checksum
  - compute the new checksum.
So if you chose to change a single pbuf, that is ok. But what if you
change 2 or 3 of them ? You would recompute the checksums as often as
you change some pbufs.

In fact, the solution is to let you perform your changes without
computing any checksum. Then, once it is over, either you call
libnet_update_checksum() by yourself, or it is called before any
writing if needed.

* Changing that behavior

NOTE: This has not been seriously tested ... Use at your own risks and
      report bugs 

You also have the choice to compute or no the checksum. Managing that
depends on the level of control you use to handle your(s) packet(s).

Of course, as checksums are computed ASAP, you cant block checksumming
at pbuf level before the pbuf is constructed. As an alternative, you
can act at the packet level.

- libnet_toggle_checksum(libnet_t *l, int mode)
  this function blocks the computation of checksums for each pbuf
  contained in each packet belonging to that context.  If you want to
  have

  Example #4.1: setting a checksum to 0

      l = libnet_init();
      libnet_toggle_checksum(l, LIBNET_OFF); //toggle off auto-checksum
      csum = 0;
  [1] udp = libnet_build_udp(..., csum, ...);
      libnet_toggle_checksum(l, LIBNET_ON); //toggle on auto-checksum
  [2] ip = libnet_build_ipv4(..., csum, ...);

  At line [1], the checksum is set to 0 and is not computed as it
  should have been at line [2] when IPs are available. However, as
  auto-checksum was turned on before the IPv4 builder is called,
  checksum for the IPv4 header is computed.

  However, what if you change your mind, for instance because you want
  to re-use later that same pbuf ? The answer is the next function.

- libnet_pbuf_toggle_checksum(libnet_t *l, libnet_ptag_t ptag, int mode)
  this function assumes there is only one packet in the context.
  Just call libnet_pbuf_toggle_checksum(l,udp, LIBNET_ON)
  
  If the requested ptag/pbuf does not have checksum, this function
  returns an error.

- libnet_packet_toggle_checksum(libnet_t *l, packet_t *pkt, int mode)
  the same as above, but for a single packet.

  If the packet contained some pbufs, they are NOT affected by the
  change:
    - if you turn off auto-checksum, pbuf previously present in the
      packet will have their checksum computed
    - if you turn on auto-checksum, pbuf previously ignoring the
      auto-checksum computation will keep ignoring it.

- libnet_pbuf_toggle_checksum_adv(libnet_t *l, packet_t *pkt, libnet_ptag_t ptag, int mode)
  this is the same function as  libnet_pbuf_toggle_checksum() but for
  the advanced interface, where you need to specify a packet.

  If the requested ptag/pbuf does not have checksum, this function
  returns an error.

   

Warning: once you mark a packet or a pbuf as "do not compute checksum
  automatically", it will keep that behavior until you change it
  explicitly



5. Building multiple packets
============================
As the main author of the former "multiple packet context queue", it
sucks! Now, handling multiple packets is fully transparent. As the
main component of libnet is no more the protocol block but the packet
itself, you just build packet, and feed any context you want with
them. Then, writing these context will send the packets contain in it.

There is one thing you need to take care of.

To be compatible with the 1.1 API, I kept the libnet_build_*()
functions. However, all these functions assume there is only one
packet in a context.

See example #3.2 and #3.3 just above for more details.

However, you can also chose to ignore the context, except for writing,
and manage packets all by yourself (see example #3.4 above).


6. Payload
===========
Each builder contains 2 arguments, payload and payload_s (size),
designed to be whatever data you want for that layer. That let you
embed any kind of data, and even creates packets for protocols that
are not yet supported in libnet (yes, it seems there are some ;-) 


* using the payload argument
For example, let's assume libnet support RFC1149 (A Standard for the
Transmission of IP Datagrams on Avian Carriers). It provides the
function:

  libnet_build_avian_carriers(...,            // some specific args
                              char *payload,  // either data or upper protocol
                              int payload_s,  // size of payload
                              libnet_t *l, 
                              libnet_ptag ptag);

Now, you need for whatever reason to add QoS as defined in RFC2549 (IP
over Avian Carriers with Quality of Service). As we dont have done
that builder, you need to provide the proper bytes by yourself. For
instance:

  Example #6.1: adding QoS to libnet_build_avian_carriers()
    char carriers_qos[QOS_LENGTH];

    set_carriers_qos(<some options>, carriers_qos);
    pigeon = libnet_build_avian_carriers( ...
                 carriers_qos,
                 QOS_LENGTH,
                 l
                 0);

    The pigeon ptag will be then build with its arguments, and the QoS
    will be appended at the end, as expected. Once this packet is
    sent, the receiver will decode it as what it is: avian carriers
    with quality of service

However, most of the time, you will use payload to put data in your
packets. That is the data that are the most changing in a
packet. During the network session, bytes at lower layers are almost
the sames in every packet: some flags change, as ack/seq numbers for
instance. However, data transported are often changing. That is why we
provide a specific builder, with a special property.

* the "resizable" pbuf : libnet_build_payload()

When you build a packet to transport data, that is the builder of your
dreams! It must be the first builder you call in your packet, so that
it is at the end of the packet, just as the data. If you dont need it
at the first packet, you can declare it with an empty payload anyway:
as long as you declare it, you reserve place you will be able to use
later.

    libnet_ptag_t
    libnet_build_pbuf_payload(u_int8_t *payload, u_int32_t payload_s, 
                          u_int32_t payload_max, 
                          libnet_t *l, packet_t *pkt, libnet_ptag_t ptag);



So, to avoid multiple memory allocation, you should allocate a well
sized buffer (eg LIBNET_PAYLOAD_LENGTH, which is defined as
0.66*LIBNET_PKT_LENGTH) :

   data = libnet_build_payload(payload1, size1, 
                               LIBNET_PAYLOAD_LENGTH, l, 0);

Here, in a single instruction you create a payload of size size1, but
which has reserved LIBNET_PAYLOAD_LENGTH bytes in memory. Then for any
subsequent usage of payload, you can use up to LIBNET_PAYLOAD_LENGTH
bytes with that function.

So, you can re-use this pbuf (notice the "data" at the end):
   data = libnet_build_payload(payload2, size2, 
                               LIBNET_PAYLOAD_LENGTH, l, data);

No more memroy allocation is made, but the payload of the packet is
feed with a different sized buffer anyway.

Very efficient and practical indeed ;-)


7. Unified name resolution
==========================

Name resolution has been redesigned, even if the old functions are
still present for compatibility reasons. However, the old functions
are build over gethostbyname() and gethostbyaddr() which are protocol
dependant.

The new API is build over getnameinfo() and getaddrinfo(), which is
protocol Independant.

Moreover, I have included the structure of addresses defined by Dug
Song in libdnet (once again, thanks to you for that nice library) That
way, compatibility between the libraries will help in future
developments. Remember he provides lots of useful conversion functions
for this address structure. 


There are 3 functions, one being a wrapper for the 2 others. The
general resolution function is libnet_resolve() : 

    int libnet_resolve(char *name, size_t size, 
	               libnet_addr_t *addr, int flags, char*errbuf);
    int libnet_resolve_ascii2addr(char *name, size_t size, 
    	               libnet_addr_t *addr, int flags, char*errbuf);
    int libnet_resolve_addr2ascii(char *name, size_t size, 
    	               libnet_addr_t *addr, int flags, char*errbuf);

Depending on what you ask, arguments can be either an input or an
output. For instance, transforming a string being an hostname to its
IP address is not the same as ... the opposite ;-) In the first
situation, the parameter "name" in libnet_resolve() will be an input,
while it will be an output in the second case.

While "name" and "addr" will control what you want, "flags" controls
how you get it:
  - conversion : set bit LIBNET_ASCII2ADDR if you want to convert from
    a string to an address, or LIBNET_ADDR2ASCII conversely.
  - set bit LIBNET_NUMERICHOST if you want to avoid name resolution,
    e.g. transforming an IP address to its corresponding string.
  - set bit LIBNET_CANONNAME to force a name resolution.

Bits LIBNET_ADDR2ASCII and LIBNET_ASCII2ADDR are of course exclusive.

So, now that you told to libnet_resolve() what you want, you just need
to supply the proper arguments:
  - "name" is a memory buffer of "size" bytes
  - "addr" is a structure 

IMPORTANT
As the new resolution functions are protocol independent, if you dont
specify a protocol by yourself, it will use PF_UNSPEC (see
getarrdinfo(3)). Then, you will have to check for the address family
returned if any.

Thus to avoid that "annoyance", there are also functions forcing the
expected address family:

    int libnet_resolve_ascii2addr4();
    int libnet_resolve_ascii2addr6();
    int libnet_resolve_addr2ascii4();
    int libnet_resolve_addr2ascii6();

The ones ending with a '4' do IPv4 lookup, while the ones ending with
a '6' do ... guess by yourself ;-)))


Name resolution by examples

* ascii2addr()

 + "IP" -> addr 

  - flags = LIBNET_ASCII2ADDR [ | LIBNET_NUMERICHOST]

    "./gai -i 1.2.3.4" and  " ./gai -i 1.2.3.4 -n" are equivalent
    as no name resolution is made.

  - flags = LIBNET_ASCII2ADDR | LIBNET_CANONNAME

    It gives the same result, but a DNS (type PTR) request is made

    ./gai -i 1.2.3.4  -c
    ascii -> addr: name=1.2.3.4 addr=1 2 3 4
    ./gai -i 217.12.3.11  -c
    ascii -> addr: name=217.12.3.11 addr=217 12 3 11  (FQDN ok)

    In both cases, you get the IP address in its numerical, but in
    the second case, you also know the address resolves.

    Thus, when using LIBNET_CANONNAME, dont forget to check the
    return value of the resolve function you call.

 + hotname -> addr

  - flags = LIBNET_ASCII2ADDR | LIBNET_NUMERICHOST

    ./gai -i google.fr -n
    libnet_resolve_ascii2addr(): unable to resolve 
    (err=-2: Name or service not known)

    This leads to an error because the expected input should have
    been an Ip address because of the -n (LIBNET_NUMERICHOST)
    makes. And a hostname was provided

  - flags = LIBNET_ASCII2ADDR 

    ./gai -i google.fr 
    A dns query (type A) is sent to the dns to get the requested IP addr.

  - flags = LIBNET_ASCII2ADDR | LIBNET_CANONNAME

   Several DNS queries are made. The first one is the same as above
   (type A) to get the expected IP address. As a name can have
   several IPs, they are all checked with a type PTR DNS query.

   ./gai -i google.fr -c
   ascii -> addr: name=google.fr addr=216 239 59 104
   ./gai -i yahoo.fr -c
   ascii -> addr: name=yahoo.fr addr=217 12 3 11  (FQDN ok)

   We retrieve here the previous results: PTR requests failed for
   google, not for yahoo.


* addr2ascii()

  - flags =  LIBNET_ADDR2ASCII

    A DNS query is made (PTR type) to retrieve the FQDN
    corresponding to the address. If no name comes back, the IP
    address is converted to a string.

    ./gai -4 1.2.3.4
    addr -> ascii: name=1.2.3.4 addr=1 2 3 4

  - flags =  LIBNET_ADDR2ASCII | LIBNET_CANONNAME

    A DNS query is made (PTR type) to retrieve the FQDN
    corresponding to the address. If no names come back, a failure
    is returned.

    ./gai -4 216.239.32.10 -c
    addr -> ascii: name=ns1.google.com addr=216 239 32 10
    ./gai -4 1.2.3.4  -c
    libnet_resolve_addr2ascii(): getnameinfo() failed (Success)

    Note: yes, it fails ... even if errno is set to success !!!

  - flags =  LIBNET_ADDR2ASCII | LIBNET_NUMERICHOST

    No DNS request is made, and the address is converted to its
    string.

    ./gai -4 1.2.3.4  -n
    addr -> ascii: name=1.2.3.4 addr=1 2 3 4


* Strange behavior

All OS are not equals in front of name resolution. Some have caches,
others dont. Some do extensive lookups, others dont, ...

See sample/gai.c for an example and bellow are the results obtained.

                             Linux   Mac OS X  Windows
                              2.6      10.3    "2k"(1)
/gai -i 1.2.3.4                ok       ok       ok
/gai -i 1.2.3.4 -n             ok       ok       ok
/gai -i 1.2.3.4 -c           ok 0:1   ok 0:1
/gai -i 217.12.3.11  -c      ok 0:1   ok 0:1

/gai -i google.fr -n          [1]     ok 1:0     [5]
/gai -i google.fr            ok 1:0   ok 1:0     ok
/gai -i google.fr -c         ok 1:X   ok 1:0     ok
/gai -i yahoo.fr -c         [2] 1:1  [3] 1:0

/gai -4 1.2.3.4              ok 0:1    [4]
/gai -4 1.2.3.4  -c         [6] 0:1    [4]
/gai -4 1.2.3.4  -n            ok      [4]

(1) Dont have the exact version of Win, and dont have the stats on
    DNS queries


[1] unable to resolve (err=-2: Name or service not known)
[2] ascii -> addr: name=yahoo.fr addr=217 12 3 11  (FQDN ok)
[3] ascii -> addr: name=yahoo.fr addr=217 12 3 11
[4] libnet_resolve_addr2ascii(): getnameinfo() failed (Unknown error: 0)
[5] unable to resolve (err=11001: No such host is known . )

X:Y means  X DNS request of type A, and Y of type PTR. When nothing is
speicied, it means there is no DNS request.

On Mac OS X, take care there is a DNS cache so there can be no DNS
request if the request is already cached.







limits
======
- Number of packets: you cannot create more that 2^64 packets.
  Beyond there, I am not responsible for the strange behavior of your
  program ;-) 
  That is because each packet is identified by a unique and global id,
  which is an u_int64_t.


API Changes
===========
- libnet_autobuild_* : they now accept a payload and a ptag
- GRE Builder
  - libnet_getgre_lentgth() renamed libnet_get_gre_length()
  - libnet_build_gre_last_sre() takes 2 more args (payload+payload_s)
- libnet_toggle_checksum(): see README.ng for details
- libnet_build_data() is replaced by libnet_build_payload() (API
  change too, see doc).
- context_queue: deprecated
- functions handling injection mode renamed from
  libnet_<action>_<mode>() to libnet_<mode>_<action>()
- libnet_gethwaddr() prototype changed to 
      libnet_addr_t* libnet_get_hwaddr(char *dev, char *errbuf);
- libnet_get_ipaddr4() prototype changed to 
      libnet_addr_t* libnet_get_ipaddr4(char *dev, char *errbuf);
- libnet_seed_prand() takes a char* instead of a libnet_t*
- plist: 
    - constructor renamed to libnet_new_plist_chain(), dont take a
    context anymore, but an errbuf instead

Compatibility preserved:
- options are now included in TPC and IPv4 builders. Having specific
  builders was too much of a pain as it requires accessing to headers
  that may not have been there already...
  So, the new API are suffixed with _ng:
    libnet_build_ipv4_ng()
    libnet_build_tcp_ng()
  In order to keep the previous program compatible, macros have been
  defined (with the old name) which call the ng functions.


**********************************************************************
*                          DEVEL KORNER                              *
**********************************************************************

Adding a new builder
====================

- name it libnet_build_<protocol>.c
- add info about it in include/libnet/libnet-headers.h
    - a constant called LIBNET_<PROTO>_H giving the size of the header
    - the structure defining the header
- add its pbuf type in include/libnet/libnet-structures.h
      #define LIBNET_PBUF_<PROTO>_H
- create a file src/libnet_build_<proto>.c from the template
  src/libnet_build_template.c.
  The 2 mandatory functions are 
      libnet_build_<proto>()
      libnet_build_pbuf_<proto>()
  For some protocols, you can also add
      libnet_autobuild_<proto>()
      libnet_build_csum_<proto>()

See comments in src/libnet_build_template.c.

Adding a new address type
=========================

Libnet already supports several layer 2 and 3 protocols, and their
associated address family. However, if one wants to add a new one,
there are several files to be modified:

- include/libnet/libnet-structures.h
  1. Add the new kind of address in the generic address structure
  2. An address is usually associated with a protocol, so add this
     protocol as LIBNET_PBUF_<type>_H to declare such a header
- include/libnet/libnet-headers.h
  Add the header associated to the protocol here.
  Dont forget  to define the length of the header when it is possible.
- include/dlt-bpf.h
  This file is mainly used when you want to write a pcap file. There
  is the way to provide the linktype expected in the header of a pcap
  file.
  So, check whether a variable DLT_<type> already exists or not, and
  then also check for the matching LINKTYPE_<type> at the end of the
  file.
- src/libnet-mode-pcap.c
  add the matching between LIBNET°PBUF_<type>_H and LINKTYPE_<type> in
  the function get_linktype()

Adding a new mode of injection (need to be completed)
==============================
I dont know which one it is possible to add, but anyway, you can have
a look at src/libnet_mode_template.c to have a ... template.

Each mode defines some functions:
  - int libnet_template_open(libnet_t *l)
    open the file descriptor, contained in l, used to write bytes

  - int libnet_template_close(libnet_t *l)
    close the file descriptor, and may perform some cleaning

  - int libnet_template_option(libnet_t *l, u_int32_t request, char *argp)
    just a wrapper to let the user manipulate the options of the file
    descriptor used to write packets if he wishes

  - int libnet_template_init(libnet_t *l, char *errbuf)
    each context contains pointers on the above functions. init()
    initializes these pointers.

These first 3 functions are accessible through the pointers located in
the libnet context. The last one is called during initialisation of the
context (see step 3 below).

Each injection mode defines 3 functions to write:
  - int libnet_template_write(libnet_t *l)
    write all packets contained in context

  - int libnet_template_write_pkt(libnet_t *l, packet_t *pkt)
    write pkt through the context, even if pkt does not belong to the
    context. Checksums in pkt are updated if needed.

  - int libnet_template_write_bytes(libnet_t *l, u_int8_t *bytes, 
                                    u_int32_t sz, int type)
     write raw bytes through the context.

So, what to do?
1. Add this new type to include/libnet/libnet-structures.h
   Check where libnet_context is defined, you will find the other
   modes.
2. Copy/paste src/libnet_mode_template.c to your own mode (should be
   something like src/libnet_mode_mynewmode.c), and fill in the blanks
3. Add support for that mode in libnet_init() (src/libnet_context.c)

If you want to add a new link layer, things are a bit more
complicated as it depends on the system.

- there are already shared functions for link layer in
  src/libnet_mode_link.c
  You'll find here some of the functions that need to be implemented
  for all the link layers.
- in src/libnet_mode_link_mynewlinkmode.c, "specialize" your own
  functions. Usually, that is libnet_open_link() and libnet_write_link()