Вы находитесь на странице: 1из 36

Exile 2000 International Coding Team

(http://www.exile2k.org)
Documentation about native raw socket programming
All rights reserved Exile Team

Free to distribute this text just keep it's integrity
Ripping is lame remember this


Questions or comments?

Nitr0gen
nitr0gen@hackersnews.com


PLEASE EXCUSE MY POOR ENGLISH, IT'S NOT MY MOTHER LANGUAGE





-----[ Forewords ]---


Well you're in it, there's no way to escape the native way of raw
socket programming. In contrast of many people thinking it's boring
or a waste of time, coding in raw socket is a good experience to learn
and is very useful sometimes. With it, you get more flexibility
to innovate new protocols, control what's really happening at
lower level. Building packet through a library is efficient but
imagine how powerfull it gets when you can code your own lib.

Actually, i'm not writing this paper to convince you how kool or
strong raw socket coding is, so i'll get to the point. Firstly i
want to notice that to understand this documentation a good knowledge
of C and networking concept's required. I introduce the ip header
first, secondly tcp header, then udp header and last but not least,
the icmp header.

The second part of this foreword is dedicated to lamers. I
know the whole world's focusing on them but please,
respect the intelectual knowledge of the author and don't rip
this text for your purposes.













-----[ Content ]---


[ IP Header ]
- Theory
- Fragmentation
- Checksum
- Examples

[ TCP Header ]
- Theory
- Example

[ UDP Header ]
- Theory
- Example

[ ICMP Header ]
- Theory
- Example

[ The Implementation ]

[ Conclusion ]

[ Appendix A ]
- Structures and Functions
- Sources

[ References ]

[ Greetings ]

























[ CHAPTER 1 ]
(IP HEADER)


---[ Theory


Well if you're interest in raw socket programming i assume you
know tcp/ip's basic. By this, i mean all layers and stuff. Ip header
is part of the NETWORK layers in tcp/ip protocol suit. Basicly ip
header is used to route packets over a network such as the internet, wan
or lan. Transmission mode of this header is unreliable datagram
because you don't have garanty that it will arrive at destination,
or even worst, packets sent aren't surely received in the order they
were delivered.

Take for example (Datagram A and B) A is sent before B, it's not
garantied that A will take the same way(Routing) as B to arrive at
destination. The result of this is what i said before, datagram aren't
surely received in the way they were delivered.As you are reading this
documentation you know it's not a tcp/ip course but a coding
documentation, therefore, i'll limit myself to coding.

As a matter of information, when you build a packet don't
forget your htons() or htonl() to respect byte ordering. Some
reader will interogate themselves and ask why i'm telling that,
i'll answer that i have been sticking 1 month to find this little
problem. PLEASE DON'T DO AS I DID!!!!


Here's an ascii art of a IP header:


0 15-16 31
+-----+-----+-----------+-----------------------+ \
| Ver | IHL | TOS | Total Length | \
| (4) | (4) | (8) | (16 ) | |
+-----+-----+-----------+--------+--------------+ |
| Identification | Flags | Frag Offset | |
| (16) | (3) | (13) | |
+-----------+-----------+--------+--------------+ |
| TTL | Protocol | Header Checksum | 20 Bytes
| (8) | (8) | (16) | |
+-----------+-----------+-----------------------+ |
| Source Ip Address | |
| (32) | |
+-----------------------------------------------+ |
| Destination Ip Address | |
| (32) | /
+-----------------------------------------------+ /
< Options >
> (if any) <
+-----------------------------------------------+
> <
< Data >
> <


Version (4 bits):
Version field is used to specify Internet Protocol version,
usually IpV4 since IpV6 hasn't been released officially yet.


IHL (Internet Header Length, 4 bits):
Ihl's the length, in 32 bits words, of the IP header. When
using no options, the value by default should be 5.


TOS (Type Of Service, 8 bits):
Tos is used to specify services needs.

There's 4 options for TOS:

*NAME* *Hex value*

1- Minimize delay 0x10
2- Maximize throughput 0x08
3- Maximize reliability 0x04
4- Minimize monatary cost 0x02

1: This is used by application who transfert
small ammounts of data and needs a fast
reponse.

2: In oposite, this is used by an application
transfering lots of data and wants to
increased his data throughput.

3: I don't know about it, will be explained next
paper.

4: I don't know about it, will be explained next
paper.

Since TOS is an experimantal feature of IP, we
won't discuss further about it in this paper,
next paper could eventually go deeper into Tos
theory.


Total Length (8 bits):
This's to specify datagrams size, headers
+ data. For example:
We got a (ip header + tcp header[syn]) without
data. Size of ip header's 20 and tcps size too,
then tot_len field will be 40.


Identification (16 bits):
Id is used to identify fragments. When
datagrams aren't fragmented this field is
useless.Id usually increments from from datagram
to datagram. Each fragment haves the same id as
the first datagram.


Flags (3 bits):
This field of Ip is used by fragmentation.
There is 4 flags:

*NAME* *Hex value*

No flags 0x00
More fragment 0x01
Don't fragment 0x02
More and Dont't frag 0x03

More frag means that there is more fragment after
this dgram, don't frag tells not to fragment that
piece and the last do both. When you fragment a
dgram,the last packet doesn't haves MF (More Frag)
set.


Fragment Offset (13 bits):
This is the offset within the packet
calculated. The first dgram gets offset 0.
This field is calculated in 64 bits. When
calculating,last offset will be equal to tot_len.


TTL (Time To Live, 8 bits):
This field is used to specify how many
hops the dgram will be able to go through. It's
decreased each time forwarded. When the TTL reach
0 the hop discard dgram and send back an icmp
message TIME EXCEED to the source. This is to
avoid infinit loop of dgram in a network.


Protocol (8 bits):
This specify the protocol for transport
layer. The value can be:

*NAME* *Hex value*

IPPROTO_TCP 0x06
IPPROTO_UDP 0x11
IPPROTO_ICMP 0x01

There's more protocol but they won't be covered in
this paper. For more information take a look at
this header who defines all constants.
'/usr/include/linux/in.h'


Header CheckSum (16 bits):
The checksum's used to verify datagrams
integrity. If data gets corrupted or modified
during transport, then it can be detected with
checksum. If checksum doesn't match dgram, it
is hardly discared without warnings. This is
annoying under coding point of view. Look at
Appendix A for the checksum function
( in_cksum() ).


Source Ip (32 bits):
The source ip of the host sending the
datagram.

Destination Ip (32 bits):
The destination ip for this datagram.



Options (Variable):
Options field will not be covered in
this paper, but a next version should.



Under programming point of view, building a Ip
Header is simply filling a structure. Since i'm using
Linux, all reference made to headers and syscalls will
be based on linux 2.2.13.




---[ Fragmentation


Basicly fragmentation is when the MTU (Maximum
Transfert Unit) is lower then the dgram total length.
So we must break it into few pieces and send it, once
at destination it rebuild the dgram. When
fragmenting, we need specific field set in Ip header.
Flag MF must be set to all fragment except the last.
Offset for the first packet must be zero. Id must be
the same for each fragment to identify which fragment
belongs to what serie of datagram piece. If Ip header
is modified in a fragment, checksum must be
recalculated. First fragments total length gets the
value of MTU and so on...




---[ Checksum


Well, calculating a header checksum isn't hard,
take a look at the Appendix A to see the function
responsible of calculating checksum. Here's the
prototype:

unsigned short in_cksum(unsigned short *addr, int len);

- unsigned short *addr : This is a pointer to your ip header.
- int len : This is the length of your ip header.

Basicly here is what the function do:

/*
* Our algorithm is simple, using a 32 bit accumulator (sum),
we add
* sequential 16 bit words to it, and at the end, fold back all
the
* carry bits from the top 16 bits into the lower 16 bits.
*/





---[ Examples


The name tells explicitly what you'll find on that
section. We assume we are on a Little Endian cpu.



/***********************************************************************/
/* Exile 2000 International Coding Team */
/* (http://www.exile2k.org) */
/* All rights reserved Exile Team */
/* Copyright 2000 (C) Nitr0gen */
/* */
/* This function basicly build a IP header */
/* WITHOUT FRAGMENTATION */
/* */
/***********************************************************************/

void buildip_nf(){ /*** Function building a IP Header ***/

struct iphdr *ip;
/*** A little step for a man, a big step for human kind ***/

ip = (struct iphdr *) malloc(sizeof(struct iphdr));
/*** Allocating dynamic memory ***/

ip->ihl = 5; /*** IP Header Length in bytes ***/
ip->version = 4; /*** IP Version ***/
ip->tos = 0; /*** Experimental (See higher for details) ***/
ip->tot_len = sizeof(struct iphdr) + 452/*** Total length of packet
***/


ip->id = htons(getuid());
/*** Identification of the packet, useless
for us ***/

ip->ttl = 255; /*** The packet can pass up
to 255 hop ***/
ip->protocol = IPPROTO_TCP; /*** If we use tcp at TRANSPORT
layer***/
ip->saddr = inet_addr("127.0.0.1"); /*** Packet source ip ***/
ip->daddr = inet_addr("127.0.0.1"); /*** Packet destination ip
***/

ip->check = in_cksum((unsigned short *)ip, sizeof(struct
iphdr));
/*** Checksum ***/

}




/***********************************************************************/
/* Exile 2000 International Coding Team */
/* (http://www.exile2k.org) */
/* All rights reserved Exile Team */
/* Copyright 2000 (C) Nitr0gen */
/* */
/* This function basicly build a IP header */
/* FRAGMENTATION of ip */
/* datagram into 2 fragments */
/* MTU = 280 bytes */
/* */
/***********************************************************************/



void buildip_f(){ /*** Function building a fragmented IP Header ***/

struct iphdr *ipf;

ipf = (struct iphdr *) malloc(sizeof(struct iphdr));

/**** FIRST FRAGMENT ***/
ipf->ihl = 5; /*** Length of header in 32 bits word */
ipf->version = 4; /*** Ip version */
ipf->tos = 0; /*** Type of service unused */
ipf->tot_len = sizeof(struct iphdr) + 256; /* Length of first
frag */
ipf->id = htons(1); /*** To identify our 2 frag */
ipf->ttl = 255; /*** Datagram can pass up to 255 hops */
ipf->protocol = IPPROTO_TCP; /*** using TCP protocol.. *whatever*
*/
ipf->saddr = inet_addr("127.0.0.1"); /*** Sending from
localhost */
ipf->daddr = inet_addr("127.0.0.1"); /*** Sending to localhost
*/
ipf->frag_off = htons(0x2000); /*** Fragment 0 and MF */
ipf->check = in_cksum((unsigned short *)ipf,sizeof(struct
iphdr)+256);
/*** Computing checksum */


/**** We should send the first fragment here ***/


/**** SECOND FRAGMENT ***/
ipf->tot_len = sizeof(struct iphdr) + 196; /*** Updating dgrams
length */
ipf->frag_off = htons(32); /*** Fragment offset ***/
ipf->check = in_cksum((unsigned short *)ipf,sizeof(struct
iphdr)+196);
/*** Recomputing checksum since we have changed some field */

/**** We should send the second fragment here ***/

}
















[ CHAPTER 2 ]
(TCP HEADER)




---[ Theory


From now on lets take a look at tcps header.
Since this is a reliable transmission mode, you
have to make a connection before transmitting
streams. Actually, what is a connection? With
tcp we call it an Handshake which investigate 3
steps. The first peer have to send a tcp SYN
segment to SYNchronize the acknowledgment number
then the second peer have to ACKnowledge the syn to
make sure it has been received. If the SYN_ACK
isn't received from first peer then the tcp's
connection state stay on SYN_SENT and keep sending
SYN to the second peer until he gets it. After SYN
reception has been confirmed by SYN_ACK we send
back a ACK to confirm the reception of SYN_ACK.
Theorycally a connection is made between both host
but if second host gets disconnected before
receiving our last ACK, we think we are connected
but we aren't. This is one of tcp's problem. Tcp
as Ip has a data integrity checksum using a pseudo
header which will be discussed later. To be sure
a segment comes from the source it claims, tcp added
a Sequence number feature which means that when
doing the handshake, first peer gives a Seq Number
then second peer ACK the SYN with her seq number set
has the first peer sended it. Second host expect the
next incoming segment to have his seq number as
specified in Acknowledgment field in last segment
sent. This method prevents misintentionned user from
hijacking connection. Take for example:

Host A < ---- TCP CONNECTION ----> HOST B

^---- HOST X (Misintentionnned user)

If there wasn't sequence number, HOST X could
send segment to HOST B claiming he's HOST A
and reset the connection. Last year
approximatly, this technique was in use.
But now, seq number a praticly random, it's
then impossible to guess.

This protocol got more security options playing with
IP options, but i'll not cover them on this version
of the paper. Tcp allow a good multiplexing way of
managing his incoming and outgoing segment. Because
of destination and source port, lot of process can
communicate together at the same time. I didn't
covered all the tcps feature because this's not a
tcp/ip guide but a programming paper but im pretty
sure you know that the protocol has good features to
keep data integrity, security and multiplexing...
These options have to cause a disadvantage somewhere
and it hurts the speed of transmissions. Did you
ever ask youself about what is a socket? Well the
term socket is oftenly used in tcps world. A socket
is simply a Ip Addresse combined with a Port number
and a socket pair is the combination of Source Ip
Addresse + Source Port + Destination Ip Addresse +
Destination port.

Tcp offer 6 major functions:


URG: Send urgent data to desintation peer.

ACK: Acknowledgement of the data. This is
keep datas integrity as explained
higher.

PSH: Push data to destination peer.

RST: Resets a connection.

SYN: Synchronize the Seq Number.

FIN: No more data to send from source host.








TCP Header Scheme:

0 15-16 31
+-----------------------+-----------------------+ \
| Source Port | Destination Port | \
| (16b) | (16b) | |
+-----------------------+-----------------------+ |
| Sequence Number | |
| (32b) | |
+-----------------------------------------------+ |
| Acknowledgement | |
| (32b) | |
+-------+------+--------+-----------------------+ 20 Bytes
| D_Off | Res | Flags | Windows | |
| (4b) | (6b) | (6b) | (16b) | |
+-------+------+--------+-----------------------+ |
| Checksum | Urgent Pointer | |
| (16b) | (16b) | |
+-----------------------+------------+----------+ |
| Options | Padding | |
| (24b) | (8b) | /
+------------------------------------+----------+ /
> DATA <
< >




Source Port (16 bits):
The source port of this segment.
Returning segment will be received on
this port.

Destination Port (16 bits):
The segments destination port.
The segment will be received from the
outgoing interface on that port.

Sequence number (32bits):
Sequence number is a good tcp
security feature. When a sement is
received, kernel tcp module verify if
the number is right. If it's not it
discard the segment. This is to avoid
misintentionned kids hijacking tcp
connections as i said previously.




Acknowledgment (32 bits):
When ACK flag's set, the value
of this field is set to the new Seq
number expecting to receive from next
segment of the other peer.


Data Offset (4 bits):
The data offset within the
header expressed in 32 bits words.
If no options, default value is 5.


Reserved (6 bits):
Reserved for futur use, it must
be 0.

Flags (6 bits):
There is 6 flags in a tcp
segment. Here the are:


URG: Urgent Pointer
ACK: Acknowledge
PSH: Push
RST: Reset
SYN: Synchronize Seq Number
FIN: No more data to send from source


Windows (16 bits):
This is to specify the next maximum
segment size. If segment exceed this value,
it must be fragmented.


Checksum (16 bits):
The checksum to keep data integrity.
The checksum is calculating with a
Pseudo-Header which i'lll explain. Here is
the structure, stolen from Tcp/Ip Volume 1
(The protocol) by W. Richard Stevens. Please
give 1 minute of silence for this incredible
man that have died, he was a awesome
writer.

Here's the struct:

struct pseudohdr {
unsigned long saddr;
unsigned long daddr;
char useless;
unsigned char protocol;
unsigned short length;
};

The header holds the source and destination
ip addresse to avoid misrouted segment.
The "useless" character is to respect 32
bits boundary. Its contains the protocol,
in this case IPPROTO_TCP and the length
of the segment.

The checksum is calculated as the Ip header:


-------------- CUT HERE -----------------

#define PSEUDO sizeof(struct pseudohdr)
#define TCPHDR sizeof(struct tcphdr)

struct pseudohdr pseudo;
struct tcphdr tcp;

pseudo.saddr = inet_addr("127.0.0.1");
pseudo.daddr = inet_addr("127.0.0.1");
pseudo.useless = htons(0);
pseudo.protocol = IPPROTO_TCP;
pseudo.length = TCPHDR + data;

tcp->check = in_cksum((unsigned short *)&pseudo, PSEUDO+TCPHDR);

-------------- CUT HERE ----------------



Urgent Pointer (16 bits):
This field is only signifiant if URG flag
is set. It points to a data area and this makes
the data urgent from destination peer point of
view.


Options (24 bits):
Options fields will not be covered in this
version of the paper.


Padding (8 bits):
The padding field is filled with 0. It is
to respect 32 bits boundary, it starts with 32
bits and ends with 32 bits.


---[ Example



/***********************************************************************/
/* Exile 2000 International Coding Team */
/* (http://www.exile2k.org) */
/* All rights reserved Exile Team */
/* Copyright 2000 (C) Nitr0gen */
/* */
/* This function basicly build a TCP header */
/* With SYN flag setted */
/* It requests for a telnet connection on localhost */
/* */
/***********************************************************************/




#define TCPHDR sizeof(struct tcphdr)
#define PSEUHDR sizeof(struct iphdr)


void build_tcp(){

struct tcphdr *tcp; /*** Tcp header ***/
struct pseudohdr *pseudo; /*** Pseudo header ***/

if ((tcp = (struct tcphdr *) malloc(TCPHDR)) == NULL){
perror("malloc()"); /*** Allocating dynamic memory ***/
return -1;
}

if ((pseudo = (struct pseudohdr *) malloc(PSEUDOHDR)) == NULL){
perror("malloc()"); /*** Allocating dynamic memory ***/
return -1;
}

memset(tcp,'\0',TCPHDR); /*** Initializing memory to \0 char
***/
memset(pseudo,'\0',PSEUDOHDR);


pseudo->saddr = inet_addr("127.0.0.1"); /*** Source Ip ***/
pseudo->daddr = inet_addr("127.0.0.1"); /*** Destination Ip
***/
pseudo->useless = 0; /*** Space reserved to respect bundary
***/
pseudo->protocol = IPPROTO_TCP; /*** We use tcp ***/
pseudo->length = htons(TCPHDR); /*** Since we don't have any
data, the length is the
tcp header only. ***/


tcp->source = htons(5000); /*** Sending from port 5000 ***/
tcp->dest = htons(23); /*** Sendting to telnetd ***/
tcp->seq = htonl(31337); /*** Initial sequence number ***/
tcp->ack_seq = htonl(0); /*** Only signifiant if ack flag set
***/
tcp->doff = 5; /*** Offset of tcp header in 32 bits word ***/
tcp->fin = 0; /*** FIN flag not set during handshake ***/
tcp->syn = 1; /*** SYN flag set, the first step of a
handshake ***/
tcp->rst = 0; /*** RST flag not set during handshake ***/
tcp->psh = 0; /*** PSH flag not set during handshake ***/
tcp->ack = 0; /*** ACK flag not set during handshake ***/
tcp->urg = 0; /*** URG flag not set during handshake ***/
tcp->window = htons(4000); /*** Maximum of next segments length
***/
tcp->urg_ptr = htons(0); /*** Only signifiant if urg flag set
***/

tcp->check = in_cksum((unsigned short
*)pseudo,TCPHDR+PSEUDOHDR);
/*** Calculating tcp checksum to avoid data corruption ***/
}

















[ CHAPTER 3 ]
(UDP HEADER)




---[ Theory


So far now, you've pass the hardcore section.
Udp is less complex rather then tcp. It doesn't
have security features, no reliability but haves
the same multiplexing as tcp. Udp haves a
higher transfert rate then tcp, which make it
useful. Like tcp, udp got a checksum too and
needs a pseudo header to calculate it.


UDP Header Scheme:


0 15-16 31
+-----------------------+-----------------------+
| Source Port | Destination Port |
| (16 b) | (16 b) |
+-----------------------+-----------------------+
| Length | Checksum |
| (16 b) | (16 b) |
+-----------------------+-----------------------+
> DATA <
< >



Source Port (16 bits):
The source port of this datagram.
Returning segment will be received on
this port.


Destination Port (16 bits):
The datagrams destination port.
The dgram will be received from the
outgoing interface on that port.


Length (16 bits):
Holds the udp datagrams length in
octets, usualy 8.


Checksum (16 bits):
Contains the datagrams checksum to
keep it's data integrity and to ensure
that it wasn't misrouted.

If you're curious about the structure,
take a look at Apendix A.





---[ Example




/***********************************************************************/
/* Exile 2000 International Coding Team */
/* (http://www.exile2k.org) */
/* All rights reserved Exile Team */
/* Copyright 2000 (C) Nitr0gen */
/* */
/* This function basicly build a UDP header */
/* */
/***********************************************************************/


void build_udp(){

struct udphdr *udp; /*** Variable declarations ***/
struct pseudohdr pseudo;

if ((udp = (struct udphdr *) malloc(sizeof(struct udphdr))) ==
NULL){
perror("Memory exhausted"); /*** Dynamic memory alloc. ***/
return ;
}


/*** Pseudo-Header's used to avoid misrouted datagrams ***/

pseudo.saddr = inet_addr("127.0.0.1"); /* Sending from localhost
**/
pseudo.daddr = inet_addr("127.0.0.1"); /* Sending to localhost
**/
pseudo.useless = htons(0); /* To respect 32 bits
boundaries */
pseudo.protocol = IPPROTO_UDP; /* Using UDP protocol */
pseudo.length = sizeof(struct udphdr); /* The sizeof udphdr
struct */

udp->source = htons(5000); /** Sending from port 5000 */
udp->dest = htons(7); /** Sending to echo server (port=7)
*/
udp->len = htons(sizeof(struct udphdr)); /* Length of udphdr
and using htons()
for bytes ordering
purposes */

udp->check = in_cksum((unsigned short *)&pseudo,sizeof(struct
udphdr));
/*** Calculating checksum ***/

}

















[ CHAPTER 4 ]
(ICMP HEADER)




---[ Theory


Basicly Internet Control Message Protocol
(ICMP) is used to report errors such as destination
unreachable, time exceed (Time to live expired) or
source quench which means that there's not enough
memory to forward the datagram in question. To
avoid infinit loop over a network, there's no
icmp message about icmp message.



ICMP Header Scheme:


0 15-16 31
+-----------+-----------+-----------------------+
| Type | Code | Checksum |
| (8 b) | (8 b) | (16 b) |
+-----------+-----------+-----------------------+
| UNUSED |
| (32 b) |
+-----------------------------------------------+
| Internet Header + 64 bits of Data |
| (32 b) |
+-----------------------------------------------+

This is the standard format for the icmp header.
But as the Types and Codes changes the unused field
become used. If unused stay unused, set it as 0.
Depending on which icmp message it is, some ip headers
field can change.



ECHO REQUEST or ECHO REPLY
--------------------------

Commonly called PING. To generate a reply, the
stack reverse source and destination ip addresse from
ip header. UNUSED field is separated into to 8 bits
field respectivly called Identifier and Sequence number
which i'll describe below.


TYPE (8 bits):
0 For echo reply
8 For echo request

CODE (8 bits):
0 Field unused for this type of message

CHECKSUM (16 bits):
The checksum is calculated as the other
headers, but the checksum field must be 0 before
calculating. To respect 32 bits boundaries, the
kernel can pad the message if his total length is
odd.

Identifier (16 bits):
This field acts the same as ip headers ID,
but for echo and reply. It helps identify which
echo reply belongs to which echo request.

Sequence Number (16 bits):
This field acts the same as ip headers ID,
but for echo and reply. It helps identify which
echo reply belongs to which echo request.

Data can be inserted in echo request but must be replied
by the host. Personally i don't get the point to put
some data into a echo request but...




DESTINATION UNREACHABLE
-----------------------

This message is used to indicate a host or
network is down, a service isn't running, the stack
isn't supporting a protocol, a fragmentation is
needed but don't fragment (DF) is set and there was
a error when routing the packet. The field UNUSED
stay unused and should be set to 0.


TYPE (8 bits):
3 Destination Unreachable


CODE (8 bits):
0 Network Unreachable
1 Host Unreachable
2 Protocol Unreachable
3 Port Unreachable
4 Fragmentation need but DF set
5 Source route failed



CHECKSUM (16 bits):
The checksum is calculated as the
last message.


UNUSED (32 bits):
Stay unused by this icmp message.


INTERNET HEADER + 64 BITS OF DATA DGRAM:
The topic is explicit. Used by
higher level protocol, if there's a port
to identify or any other field.



SOURCE QUENCH
-------------

Source Quench error message happens
when a host or gateway doesn't have enough
buffer space to queue the received packet
to forward it. To warn the host it generates
a source quench icmp.


TYPE (8 bits):
4 Source Quench


CODE (8 bits):
0 Unused


CHECKSUM (16 bits):
The checksum is calculated as the
last message.


UNUSED (32 bits):
Stay unused by this icmp message.


INTERNET HEADER + 64 BITS OF DATA DGRAM:
The topic is explicit. Used by
higher level protocol, if there's a port
to identify or any other field.



REDIRECT
--------

A redirect message i sended when there's
a shorter path to arrive at a specify destionation.
Take for example:

Johnny sends a packet to N network. It's
route table tells by d efault to send it to
Gateway #1 but when gateway1 receives the
packet it finds a shorter way to arrive
at destination. It sends a REDIRECT
to the source placing the new gateway ip
into the UNUSED field.


There's one exeption, when IP source routing is
enabled in ip header but i didn't talked about ip
options so i'll myself to this.


TYPE (8 bits):
5 Redirect


CODE (8 bits):
0 Redirect datagrams for a Network
1 Redirect datagrams for a Host
2 Redirect datagrams for a TOS and Network
3 Redirect datagrams for a TOS and Host


CHECKSUM (16 bits):
The checksum is calculated as the
last message.


GATEWAY INTERNET ADDRESS (32 bits):
Ip address of the a nearest gateway
to send packet.


INTERNET HEADER + 64 BITS OF DATA DGRAM:
The topic is explicit. Used by
higher level protocol, if there's a port
to identify or any other field.




TIME EXCEED
-----------

That message is sent when a packets Time To
Live(TTL) has expired or when the packet reassembly
time has exceed.


TYPE (8 bits):
11 Time Exceed


CODE (8 bits):
0 Time To Live Exceed (TTL)
1 Fragment reassembly time exceeded


CHECKSUM (16 bits):
The checksum is calculated as the
last message.


UNUSED (32 bits):
Stay unused by this icmp message.


INTERNET HEADER + 64 BITS OF DATA DGRAM:
The topic is explicit. Used by
higher level protocol, if there's a port
to identify or any other field.




PARAMETER PROBLEM
-----------------

Parameter problem is sent back when
a datagrams got bad values in his options,
TOS or any invalid field. A pointer to the
bad field replace the UNUSED field.


TYPE (8 bits):
12 Parameter problem


CODE (8 bits):
0 Pointer indicates the error


CHECKSUM (16 bits):
The checksum is calculated as the
last message.


POINTER (8 bits):
Only signifiant if CODE = 0. It
points to the area where the error is.


UNUSED (24 bits):
Stay unused by this icmp message.


INTERNET HEADER + 64 BITS OF DATA DGRAM:
The topic is explicit. Used by
higher level protocol, if there's a port
to identify or any other field.




TIMESTAMP REQUEST and TIMESTAMP REPLY
-------------------------------------

This is the last time the packet was touched
in seconds since midnight UT. When the packet's
sent the time is inserted and when replied, the
time is inserted after the first timestamp. This
way we can identify how far the peer is from us.


TYPE (8 bits):
13 Timestamp Request
14 Timestamp Reply


CODE (8 bits):
0 Make ID and Seq Num signifiant


CHECKSUM (16 bits):
The checksum is calculated as the
last message.

IDENTIFIER (16 bits):
Only signifiant if Code = 0. It
helps match reply with request.


SEQUENCE NUMBER (16 bits):
Only signifiant if Code = 0. It
helps match reply with request.



NETMASK REQUEST and NETMASK REPLY
---------------------------------

This icmp message returns the network mask
of the host sending the message. To generate a
reply, it reverse source and destinaiton ip
address, insert the subnet mask into the field,
recompute the checksum and send back. If the
sender doesn't know his own ip, he puts 0 into
the source ip address field and the reply will
be broadcast.



TYPE (8 bits):
17 Netmask Request
18 Netmaks Reply


CODE (8 bits):
0 Make ID and Seq Num signifiant


CHECKSUM (16 bits):
The checksum is calculated as the
last message.

IDENTIFIER (16 bits):
Only signifiant if Code = 0. It
helps match reply with request.


SEQUENCE NUMBER (16 bits):
Only signifiant if Code = 0. It
helps match reply with request.







---[ Example




/***********************************************************************/
/* */
/* Exile 2000 International Coding Team */
/* (http://www.exile2k.org) */
/* All rights reserved Exile Team */
/* Copyright 2000 (C) Nitr0gen */
/* */
/* This function basicly build a ICMP message (PING) */
/* */
/***********************************************************************/



void icmp_build(){

struct icmphdr *icmp;

icmp = (struct icmphdr *) malloc(sizeof(struct icmphdr));

icmp->type = ICMP_ECHO; /*** ECHO REQUEST */
icmp->code = 0; /*** Id and Sequence field signifiant */
icmp->un.echo.id = 0; /*** To identify ping reply */
icmp->un.echo.sequence = 0; /*** To identify ping reply */
icmp->checksum = 0; /*** Checksum field must be 0 before
calculating */

icmp->checksum = in_cksum((unsigned short *)icmp,sizeof(struct
icmphdr));
/*** Computing checksum */

}

















[ CHAPTER 5 ]
(THE IMPLEMENTATION)


---[ Theory

After all this theory about protocol
headers, we must leave the books and go
through the implementation. Basicly what i
describe here is how to create a socket
using raw level, filling the good structure
for the socket and communicating at this
low level.

First, we will go through a source
and i'll explain every lines. Let's go:


int sock, optval; /*** Socket file descriptor ***/
struct sockaddr_in peer; /*** Structure used by sendto() ***/


So far, if you don't understand you better
get a book about socket programmin g under
unix environment.

if ((sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP)) == -1){
perror("Failed to cook socket");
return -1;
}


These lines build a socket using TCP
protocol for transport layer. The socket
is SOCK_RAW to permit raw access.
AF_INET is because we are on the internet.
So from now, if socket() returns a error,
perror() display the content of errno and
return the function.

setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&optval,sizeof(int));



This function tells the socket that we
work at IPPROTO_IP level and the we'll
include the ip header (IP_HDRINCL) into
the packet sent. optval and sizeof(int)
isn't signifiant for this option so i won't
discuss about it.


peer.sin_family = AF_INET;
peer.sin_port = htons(23);
peer.sin_addr.s_addr = inet_addr("127.0.0.1");


Here we fill up the sockaddr_in structure
used by sendto(). We tell that its a
Internet family protocol (AF_INET). The
destination port is 23. Again we do a
htons() for byte ordering. Then we set
the destination address using inet_addr()
to convert address into binary.

And at this point we should build our
packet. I'll take for asset that after all
this theory you're able, so it's a kind of
exercise.


sendto(sock, packet, strlen(packet),0,(struct sockaddr
*)&peer,sizeof(struct sockaddr));



We then send the packet on sock for
strlen(packet) length. After we got the 0
because we don't specify any flags. There's
4 flags:

MSG_OOB This send a Out Of Bound
packet increasing his
priority.

MSG_DONTROUTE Don't look at the route
table and send directly to
the interface.

MSG_DONTWAIT Normally snedto() can block
But when specified, sendto
will not block and return
EAGAIN.

MSG_NONSIGNAL Asks to n ot send SIGPIPE
signal when a stream
oriented connection fails
or disconnects.


Then we put peer to specify protocols
family, destination port and destination
addresse. We cast it because sendto expects
to have a pointer of struct sockaddr. Then
we specify the struct sockaddr length and
the datagram's sent!

To make sure you understand, write this
example and try to get back the packet
and print the result. I've done a source
code to look if you've got problems.

Hint: man recv

good luck

















-----[ Conclusion ]---




From now on, i've done the best as i can
to build a complete and good paper about the subject.
i hope you enjoyed this text and for sure that it
learned you how to code using raw socket. That
documentation helped me understands some things i
wasn't sure about or even things that i had never
heard before. Finally i would like to profit of
this moment to notice that i am officially telling
publicly that in short time i'll release a nmap
like portscanner. I'm trying to improve speed
and coding style to make it readable to ordinary
people like me. This project is named ESCAN and
include many features like, connect scan, stealth,
half open, decoys, logging. A Beta version should
be released as soon as i can. To follow the
development http://www.exile2k.org


c0de c0de c0de and c0de again people!!!!

















[ Appendix A ]
(Structures and Functions)






---[ IP HEADER STRUCT



struct iphdr {

#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ihl:4;
unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned int version:4;
unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
u_int8_t tos;
u_int16_t tot_len;
u_int16_t id;
u_int16_t frag_off;
u_int8_t ttl;
u_int8_t protocol;
u_int16_t check;
u_int32_t saddr;
u_int32_t daddr;
/*The options start here. */
};






---[ PSEUDO HEADER STRUCTURE



struct pseudohdr {
unsigned long saddr;
unsigned long daddr;
char useless;
unsigned char protocol;
unsigned short length;
};





---[ TCP HEADER STRUCTURE




struct tcphdr {
__u16 source;
__u16 dest;
__u32 seq;
__u32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
res2:2;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
res2:2,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
#error "Adjust your <asm/byteorder.h> defines"
#endif
__u16 window;
__u16 check;
__u16 urg_ptr;
};





---[ UDP HEADER STRUCTURE



struct udphdr {
__u16 source;
__u16 dest;
__u16 len;
__u16 check;
};





---[ ICMP HEADER STRUCTURE




struct icmphdr {
__u8 type;
__u8 code;
__u16 checksum;
union {
struct {
__u16 id;
__u16 sequence;
} echo;
__u32 gateway;
struct {
__u16 __unused;
__u16 mtu;
} frag;
} un;
};





---[ CHECKSUM CALCULATING FUNCTION




/*
* in_cksum --
* Checksum routine for Internet Protocol
* family headers (C Version)
*/
unsigned short in_cksum(unsigned short *addr, int len)
{
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;

/*
* Our algorithm is simple, using a 32 bit accumulator (sum),
we add
* sequential 16 bit words to it, and at the end, fold back all
the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}

/* mop up an odd byte, if necessary */
if (nleft == 1)
{
*(u_char *) (&answer) = *(u_char *) w;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low
16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}







----[ Sources


/***********************************************************************/
/* */
/* Exile 2000 International Coding Team */
/* (http://www.exile2k.org) */
/* All rights reserved Exile Team */
/* Copyright 2000 (C) Nitr0gen */
/* */
/* This function basicly build a ICMP message (PING) */
/* including Ip header */
/* */
/* Your almost done! Compile the example and enjoy */
/* understanding my rustic code */
/* */
/***********************************************************************/


#include <stdio.h>

#include <linux/ip.h>
#include <linux/icmp.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>




unsigned short in_cksum(unsigned short *addr, int len);


int main(){

int sock, optval;
char *packet, *buffer;

struct icmphdr *icmp;

struct sockaddr_in peer;
struct iphdr *ip;


ip = (struct iphdr *) malloc(sizeof(struct iphdr));
icmp = (struct icmphdr *) malloc(sizeof(struct icmphdr));
packet = (char *) malloc(sizeof(struct iphdr) + sizeof(struct
icmphdr));
buffer = (char *) malloc(sizeof(struct iphdr) + sizeof(struct
icmphdr));


ip = (struct iphdr *) packet;
icmp = (struct icmphdr *) (packet + sizeof(struct iphdr));


ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
ip->tot_len = sizeof(struct iphdr) + sizeof(struct icmphdr);
ip->id = htons(getuid());
ip->ttl = 255;
ip->protocol = IPPROTO_ICMP;
ip->saddr = inet_addr("127.0.0.1");
ip->daddr = inet_addr("127.0.0.1");


sock = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&optval,sizeof(int));

icmp->type = ICMP_ECHO;
icmp->code = 0;
icmp->un.echo.id = 0;
icmp->un.echo.sequence = 0;
icmp->checksum = 0;

icmp->checksum = in_cksum((unsigned short *)icmp,sizeof(struct
icmphdr));

ip->check = in_cksum((unsigned short *)ip, sizeof(struct
iphdr));



peer.sin_family = AF_INET;
peer.sin_addr.s_addr = inet_addr("127.0.0.1");

sendto(sock,packet,ip->tot_len,0,(struct sockaddr
*)&peer,sizeof(struct sockaddr));

recv(sock,buffer,sizeof(struct iphdr)+sizeof(struct icmphdr),0);
printf("Received the ECHO REPLY\n");

close(sock);
return 0;
}








/***********************************************************************/
/* */
/* Exile 2000 International Coding Team */
/* (http://www.exile2k.org) */
/* All rights reserved Exile Team */
/* Copyright 2000 (C) Nitr0gen */
/* */
/* This function basicly build a UDP datagram */
/* including Ip header and send it to local echo server */
/* */
/* To make the lab successful please enable echo server: */
/* */
/* - pico /etc/inetd.conf */
/* - Uncomment the echo server (udp one) */
/* - killall -HUP inetd */
/* */
/* Your almost done! Compile the example and enjoy */
/* understanding my rustic code */
/* */
/***********************************************************************/


#include <stdio.h>

#include <linux/ip.h>
#include <linux/udp.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>




unsigned short in_cksum(unsigned short *addr, int len);



int main(){

int sock, optval;
char *packet, *buffer;

struct udphdr *udp;
struct pseudohdr {
unsigned long saddr;
unsigned long daddr;
char useless;
unsigned char protocol;
unsigned short length;
}pseudo;

struct sockaddr_in peer;
struct iphdr *ip;


ip = (struct iphdr *) malloc(sizeof(struct iphdr));
udp = (struct udphdr *) malloc(sizeof(struct udphdr));
packet = (char *) malloc(sizeof(struct iphdr) + sizeof(struct
udphdr) + 12);
buffer = (char *) malloc(sizeof(struct iphdr) + sizeof(struct
udphdr) + 12);


ip = (struct iphdr *) packet;
udp = (struct udphdr *) (packet + sizeof(struct iphdr));


ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
ip->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) +12;
ip->id = htons(getuid());
ip->ttl = 255;
ip->protocol = IPPROTO_UDP;
ip->saddr = inet_addr("127.0.0.1");
ip->daddr = inet_addr("127.0.0.1");


sock = socket(AF_INET,SOCK_RAW,IPPROTO_UDP);
setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&optval,sizeof(int));

pseudo.saddr = inet_addr("127.0.0.1");
pseudo.daddr = inet_addr("127.0.0.1");
pseudo.useless = htons(0);
pseudo.protocol = IPPROTO_UDP;
pseudo.length = sizeof(struct udphdr) + 12;


udp->source = htons(5000);
udp->dest = htons(7);
udp->len = htons(sizeof(struct udphdr) + 12);
udp->check = in_cksum((unsigned short *)&pseudo,sizeof(struct
udphdr) + sizeof(struct pseudohdr) + 12);

ip->check = in_cksum((unsigned short *)ip, sizeof(struct
iphdr));


strcpy((packet+sizeof(struct iphdr) + sizeof(struct udphdr)),"Hello
World");

peer.sin_family = AF_INET;
peer.sin_addr.s_addr = inet_addr("127.0.0.1");
peer.sin_port = htons(7);

sendto(sock,packet,ip->tot_len,0,(struct sockaddr
*)&peer,sizeof(struct sockaddr));

recv(sock,buffer,sizeof(struct iphdr)+sizeof(struct udphdr)+13,0);

buffer += (sizeof(struct iphdr)+sizeof(struct udphdr));
printf("Reply from Echo server:\t%s\n",buffer);

close(sock);
return 0;
}
















[ References ]



Tcp/Ip Illustrated Volume 1 (The Protocol)
By W. Richard Stevens (Addison Wesley)

Tcp/Ip Illustrated Volume 2 (The implementation)
By Gary R. Wright and W. Richard Stevens (Addition Wesley)

Take a look at:
http://www.exile2k.org Exile Team home page
http://www.hexedit.com HNS home page
http://www.eEyes.com eEyes home page

















[ Greetings ]



Special thanx to:
My Exile team bro's: Mayhem(Tutu rose emulator),
Rix(Assembly wh0re),
Kraken(Saleter dhypee),
Ehoba(Pas toi!!!),
Liks(Erm...)

or Europeen wh0res kinda synonyms =]
---> keep it kool guys!

#rhino9 peeps: Colonwq(Gotta learn you howto drink),
Hexedit(Lucky to be yourself),
Binf(Mon mentor de hacking y0),
Klog(Bleh j00),
zorkeres(Still sickshit addict?),
RcLocal(The french skill0rz),
and others

People who supported me even if i was newbie: Utopiste,
Wyzeman...

~ My parents who made it possible during 1982's night... ~

God bless people i forget...





Nitr0gen Exile Team 2000 Rock on!
nitr0gen@hackersnews.com