FC2ブログ
--.--
--
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

01.28
Wed
なるほど
http://aoking.hatenablog.jp/entry/20121109/1352457273
http://d.hatena.ne.jp/toshi_hirasawa/20081105/1225885030
http://blog.livedoor.jp/hiroumauma/archives/1385768.html
スポンサーサイト
comment 0 trackback 0
11.05
Mon
IPヘッダを自作してみます

なにをやってるのかはコメントたくさん書きました

忘れた時の自分のために

送信先IPと送信元IPを任意に変えれますけど、場合によっちゃあれなのであれです

SYNだけ送ります

ではコード


/*
	IPヘッダから自作してTCPセグメントを送受信
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
/*
	BSD系のヘッダ構造体の定義を使う為のdefine
*/
#define __FAVOR_BSD
#include <netinet/tcp.h>
#include <arpa/inet.h>

/*
	これはMSS(Max Segment Size)と言って
	Ethernetフレーム(1518byte)のサイズから
	Ethernetヘッダ: 14byte
	FCS: 4byte
	IPヘッダ: 20byte
	TCPヘッダ: 20byte
	を引き算した値になる
	1460 = 1518 - 14 - 4 - 20 - 20 
*/
#define MSS 1460 

/*

	IPヘッダとTCPヘッダのチェックサムの出し方

	IPヘッダは、オプションなしの場合はIPヘッダ構造体の先頭から20octetを
	チェックサムの値として算出する


	TCPヘッダの場合、IPヘッダとTCPヘッダの2つの部分でチェックサムをとる
	ただし、ここでのIPヘッダは擬似ヘッダといってチェックサムを算出するためだけに作る
	(送信はできない)

	擬似IPヘッダの構造

	+------------------------------------------------------------------------------------+
	|                          送信元IPアドレス(32bit)                                    |
	+------------------------------------------------------------------------------------+
	|                          送信先IPアドレス(32bit)                                    |
	+----------------+-----------------------+-------------------------------------------+
	| 常にゼロ(8bit)  |プロトコルタイプ(8bit)  |IP上のプロトコルのヘッダ長とデータ長(16bit)  |
	+----------------+-----------------------+-------------------------------------------+
	|                                                                                    | 
	|                                                                                    |
	|                                                                                    | 
	|	     ここにIPヘッダのプロトコルタイプで示されたプロトコルのヘッダが来る               |
	|                                                                                    |
	|                                                                                    | 
	|                                                                                    |
	+------------------------------------------------------------------------------------+

	このヘッダ全体のチェックサムをとる
	ただし擬似IPヘッダは送信できない!!


*/
unsigned short checksum(unsigned short *ptr , int size)  
{  
    int index = 0;  
    int sum = 0;  
    short int proc = 0;  
	unsigned short int result;
	
    for (index = 0;index<size;index+=2){  
          
            sum += *(ptr++);  
    }  
  
    short int carry = sum >> 16;  
    
    short int main = 0x0000ffff & sum;
    
    sum = main+carry;  
  
	result = ~(sum);
	
    return result;  
}  






/*
	送信時に使うヘッダ
	受信時に使うヘッダは構造体で定義しない
	なぜなら、IP,TCPヘッダのオプションでヘッダ自体のサイズが変わるので。
	送信時にオプションをつける予定はいまのところない
*/
typedef struct {
	struct ip iphr;
	struct tcphdr tcphr;
	unsigned char data[MSS];
}PACKET;


/*
	TCP ヘッダのチェックサムを求めるときに使う擬似IPヘッダ
	12byte = 12octet = 96bit
*/
typedef struct {
	struct in_addr SRC_IPADDR;
	struct in_addr DST_IPADDR;
	unsigned char ZERO;
	unsigned char PROTO;
	unsigned short int LENGTH;
} DUMMY_IPHDR;


typedef struct {
	DUMMY_IPHDR piphdr;
	struct tcphdr tcphr;
}DUMMY_PACKET;




/*
	送信可能なパケットを作成する
	flagsに指定するのは、TH_SYNやTH_ACKなどの
	netinet/tcp.hでdefineされている値のor演算したもの

	netinet/tcp.hから抜粋
	#  define TH_FIN	0x01
	#  define TH_SYN	0x02
	#  define TH_RST	0x04
	#  define TH_PUSH	0x08
	#  define TH_ACK	0x10
	#  define TH_URG	0x20

	以下理由:

	+--------------+--------------------+---------------+
	|th_off(4bit)  |th_x2(6bit) reservd |th_flags(6bit) |
	+--------------+--------------------+---------------+

	th_flagsの中身。それぞれ1bit * 6 = 6bit 
	+---+---+---+---+---+---+
	| U | A | P | R | S | F |
	| R | C | S | S | Y | I |
	| G | K | H | T | N | N |
	+---+---+---+---+---+---+
	
	th_x2を4bitで宣言しておいて、
	th_flagsを8bitで宣言することで
	4bit(th_off) + 4bit(th_x2) + 2bit(th_x2用だけど、8bit宣言してるth_flagsの上位2bit) + 6bit(th_flagsの本体)
	つまり、th_flagsの上位2bitはth_x2のためのものでフラグには関係ない

	0000 | 0000 00|00 0000


	maketcpacket
		(	
			PACKETの構造体へのポインタ , 送信データへのポインタ , データのサイズ ,
			送信元IPアドレス                    , 送信元ポート           ,
			宛先IPアドレス                      , 宛先ポート             ,
			Time To Live                        , TCPのシーケンス番号    , TCPの確認応答番号 ,
			TCPセグメントを一度に受信できる最大サイズ(ウィンドウサイズ)  , TCPフラグ 
		)

*/

void maketcpacket
	(
		PACKET  *hptr, unsigned char *dataptr , int datasize ,
		char *srcip           , unsigned short srcport , 
		char *dstip           , unsigned short dstport ,
		unsigned char   ttl   , int seq                , int ack      ,
		unsigned short 	win   , unsigned char flags  
	)
		{

			/*TCPヘッダのチェックサムを出すために擬似のパケットを作る*/
			/*擬似のパケットは擬似のIPヘッダが先頭につく*/
			/*ただし、TCPヘッダは擬似じゃないので、あとで送信用の構造体のTCP部にコピーする*/
			DUMMY_PACKET dummypacket;
			memset(&dummypacket , 0 , sizeof(DUMMY_PACKET));
			memset(hptr , 0 , sizeof(PACKET));

			/* 文字列のIPアドレスをビット列に変換 */
			inet_aton(srcip , &hptr->iphr.ip_src);
			inet_aton(dstip , &hptr->iphr.ip_dst);
			
			/* ttlを設定 */
			hptr->iphr.ip_ttl = ttl;
			
			/* ip version */
			hptr->iphr.ip_v   = IPVERSION;
			
			/* ip ヘッダの長さ(20byte) の1/4の値*/
			hptr->iphr.ip_hl  = 5;

			/*ipヘッダの長さ + tcpヘッダの長さ + データの長さ*/
			/*送信時オプション無しでやるつもりなのでそれぞれ20*/
			hptr->iphr.ip_len = htons(20 + 20 + datasize);

			/*フラグメントされた時のなんか.0でいいっぽい*/
			hptr->iphr.ip_id  = htons(0);
					
			/*フラグメントするかどうか。先頭2bitがフラグで、後半がオフセットっぽいが*/
			/*IP_DF(Don't flag)という定義済みを使う*/
			hptr->iphr.ip_off = htons(IP_DF);

			/*IPの上に乗るプロトコルの指定.ここではTCPしか扱わない*/
			hptr->iphr.ip_p   = IPPROTO_TCP; 

			/*算出前に0指定*/
			hptr->iphr.ip_sum = 0;

			/*チェックサムを求める*/
			hptr->iphr.ip_sum = checksum( (unsigned short int *)&hptr->iphr , sizeof(hptr->iphr) );
			 
			
			/*擬似IPヘッダに色々設定*/
			inet_aton( srcip  , &dummypacket.piphdr.SRC_IPADDR);
			inet_aton( dstip  , &dummypacket.piphdr.DST_IPADDR);
			dummypacket.piphdr.ZERO = 0;
			dummypacket.piphdr.PROTO = IPPROTO_TCP;
			dummypacket.piphdr.LENGTH = htons(20 + datasize);
				


			/*TCP ヘッダ*/
			/*htonlは32bit,htonsは16bitっぽいねなんか*/
			/*フィールド値で16bit取るものにはhtons,32取るものにはhtonl使えばいいっぽいぞ*/
			/*netinet/in.hに書いてある*/
			dummypacket.tcphr.th_sport = htons(srcport);
			dummypacket.tcphr.th_dport = htons(dstport);
			dummypacket.tcphr.th_seq   = htonl(seq);	
			dummypacket.tcphr.th_ack   = htonl(ack);	
			dummypacket.tcphr.th_off   = 5;
			dummypacket.tcphr.th_flags = flags;
			/*応答確認しなくても一挙に送れるセグメントの最大サイズ*/
			dummypacket.tcphr.th_win   = htons(win);
			dummypacket.tcphr.th_sum   = 0;
			dummypacket.tcphr.th_urp   = htons(0);
			dummypacket.tcphr.th_sum   = checksum((unsigned short int *)&dummypacket , sizeof(dummypacket)); 
			/*擬似ヘッダのTCPヘッダ部分のみを送信用ヘッダのTCP部にコピー:*/
			bcopy((unsigned char *)&dummypacket.tcphr ,(unsigned char *)&hptr->tcphr , sizeof(dummypacket.tcphr));
			bcopy((unsigned char *)dataptr , (unsigned char *)&hptr->data , datasize);	

		}

/*ソケットを作ってオプションを設定*/
int makerawsocket(void)
{
	int sock;
	int on = 1;
	
	//最後の引数に IPPROTO_RAWを指定すると送信はできても受信できなくなる
	//のでIPPROTO_TCPを指定して、setsockoptでIP_HDRINCLを有効にする
	//
	//PF_INETはAF_INETに同じ
	//
	if ((sock = socket(AF_INET , SOCK_RAW , IPPROTO_TCP)) < 0)
	{
		perror("socket");
		exit(EXIT_FAILURE);
	}

	//IPヘッダを含める処理
	if ( (setsockopt(sock , IPPROTO_IP , IP_HDRINCL , &on , sizeof(on))) < 0)
	{
		perror("setsockopt");
		exit(EXIT_FAILURE);
	}

	return sock;
}

/* sockaddr_in に色々設定するだけのもの */
void setaddrin(struct sockaddr_in *ptr , char *ipaddr , unsigned short port)
{
	memset(ptr , 0 , sizeof(struct sockaddr_in));
	ptr->sin_family = AF_INET;
	ptr->sin_port   = htons(port);
	inet_aton(ipaddr , &ptr->sin_addr);
}



/*recvfromが無差別に受信してしまうのでIPアドレスとポートで送信元を判別*/
/*よくないやり方だと思う*/
/*bindで自分のアドレスとソケットをくっつけてるのになんで無差別に受信するんだろう*/
int myrecvfrom(int sock,PACKET *buf,int size,int flag,struct sockaddr_in *addr,int *addrsize,int rawip,int sport)
{

	while(1)
	{
		
		recvfrom(sock , (char *)buf , size , flag , (struct sockaddr *)addr , addrsize);

		if ( (buf->iphr.ip_src.s_addr == rawip) &&(ntohs(buf->tcphr.th_sport) == sport) )break;
	}

}




int main(void)
{
	PACKET sendpacket;
	PACKET recvpacket;

	//ソケットを作る	
	int sock = makerawsocket();
	
	//アドレス構造体を宣言
	struct sockaddr_in myaddr;
	struct sockaddr_in toaddr;
	
	//このIPアドレスでIPヘッダを作る
	char toipaddr[] = "127.0.0.1"; //宛先IPアドレス
	char myipaddr[] = "127.0.0.1"; //送信元IPアドレス
		
	//送信先ポート番号と送信元ポート番号
	unsigned short int toport = 81;
	unsigned short int myport = 44210;
	
	//送信するデータのサイズ
	int datasize = 0;

	//アドレス構造体の長さ
	int toaddrlen = sizeof(toaddr);

	//アドレス情報を設定	
	setaddrin(&toaddr , toipaddr , toport);
	setaddrin(&myaddr , myipaddr , myport);


	//意味ないじゃん〜
	if (bind(sock , (struct sockaddr *)&myaddr , sizeof(myaddr)) < 0)
	{
		perror("bind");
		exit(EXIT_FAILURE);
	}

	//送信するパケットを作る
	maketcpacket(
					&sendpacket, NULL    , datasize , 
					myipaddr   , myport  , 
					toipaddr   , toport  ,
					50         , 123     , 0 ,
					8192       , TH_SYN
				);

	//送信
	if ( (sendto(sock , (char *)&sendpacket , 40 , 0 , (struct sockaddr *)&toaddr , sizeof(toaddr) ) < 0))
	{
		perror("sendto");
		exit(EXIT_FAILURE);
	}

	//受信
	myrecvfrom(sock , &recvpacket , 40 , 0 , &toaddr , &toaddrlen , toaddr.sin_addr.s_addr , toport);

	//ヘッダの情報をちょいと表示
	printf("srcaddr: %s\n" , inet_ntoa(recvpacket.iphr.ip_src));
	//送信元ポート
	printf("srcport: %d\n" , ntohs(recvpacket.tcphr.th_sport));
	//どのフラグが立っているか
	printf("tcpflag: %x\n" , recvpacket.tcphr.th_flags);

	
	close(sock);

	return 0;
}




comment 0 trackback 0
06.15
Fri
いちいちアドレスを設定したり構造体を定義するのはめんどいので、

TCP用にらくできるのを書いてみた。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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


#define True  1
#define False 0



/*
	
	以下の関数はTCPでネットワークプログラミングを行う上で基礎的な機能を提供します
	
	・tcpmake           新しいTCP用のソケットファイルディスクリプタを作る
	・tcphang           指定のホストに接続する
	・tcpwait           サーバになる
	・tcpaccept         クライアントを受け付ける                 *b
	・tcpGetDataExactly サイズ分正確に受信する                   *b
	・tcpGetHTTPHeader  \r\nで区切られるヘッダ部分のみ受信する 

    *bはブロッキングな関数
*/




/*
  -----------------------------------------------------------------------
  int tcpmake(void)
  

   tcp用のソケットを作成します
 
  return -1      異常終了
  return それ意外   ソケットファイルディスクリプタ
  -----------------------------------------------------------------------
 */

int tcpmake(void){
	
	int fd = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP);
	
	if (fd < 0)
	{
		return -1;
	}else{
		return fd;
	}
	
	
}




/*
	-----------------------------------------------------------------------
	int tcpwait
		(
			int ソケットファイルディスクリプタ , char *バインドするIPアドレス ,  
			int バインドするポート , int 接続キューの大きさ  
		)
		
	クライアントからの接続を待機できるように準備します
	
	return 0 正常終了
	return 1 異常終了
	-----------------------------------------------------------------------
*/


int tcpwait(int sockfd , char *ipaddress , int port , int backlog)
{
	struct sockaddr_in server;
	server.sin_port = htons(port);
	server.sin_family = AF_INET;
	inet_aton(ipaddress , &server.sin_addr);
	
	if (bind(sockfd , (struct sockaddr *)&server , sizeof(server)) == -1)
	{
		return 1;
	}
	
	if (listen(sockfd , backlog) == -1)
	{
		return 1;
	}
	
	return 0;
}

/*
	-----------------------------------------------------------------------------
	int tcpaccept
	(
		int ソケットファイルディスクリプタ
	)

	クライアントを一人acceptして新しいソケットファイルディスクリプタを返します
	構造体を返さないので、接続してきた人のIPとかはわかりません
	
	return -1    失敗
	return それ以外 成功
	-----------------------------------------------------------------------------
 */


int tcpaccept(int fd)
{
	
	struct sockaddr_in clientaddr;
	int len = sizeof(clientaddr);
	
	int newsock = accept(fd , (struct sockaddr *)&clientaddr , &len);
	
	return newsock;
	
}






/*	
	-----------------------------------------------------------------------
	int tcphang
		(
			int ソケットファイルディスクリプタ char *IPアドレス , int ポート番号
		)
	
	ipaddressのportに接続します。
	これはconnect関数で使うsockaddr_inを隠蔽します。
	
	return 0 正常に接続
	return 1 接続に失敗
	
	*補足*
	connect関数においての煩瑣な作業を軽減します
	-----------------------------------------------------------------------
*/

int tcphang(int sockfd , char *ipaddress , int port)
{
	
	struct sockaddr_in server;
	
	server.sin_family = AF_INET;
	server.sin_port = htons(port);
	inet_aton(ipaddress , &server.sin_addr);
	int len = sizeof(server);
	
	int result = connect(sockfd , (struct sockaddr *)&server , len);
	
	return result * -1;
	
}




/*
	-----------------------------------------------------------------------
	int tcpGetDataExactly
		(
			int ソケットのファイルディスクリプタ , char *データを格納するための文字型配列 ,
			int 受信するサイズ
		)
		
	return 0  正常にsize分受信した
	return -1 途中で接続が切れた

	*補足*
	指定されたsize分正確に受信しptrに書き込むと思います
	接続が切れるか正確にsize分受信できるまでブロッキングします
	-----------------------------------------------------------------------
*/

int tcpGetDataExactly(int sockfd , char *ptr ,  int size)
{
	int allrecvedsize = 0;
	int justrecvedsize = 0;
	while (True){
		
		justrecvedsize = recv(sockfd , ptr + allrecvedsize , size - allrecvedsize , 0);
		allrecvedsize += justrecvedsize;
		
		if (allrecvedsize == size){
				return 0;
		}

		if (justrecvedsize == 0){
			
			if (allrecvedsize == size){
				return 0;
			}else{
				return -1;
			}
		}
	}
}




/*
	-----------------------------------------------------------------------
	int tcpGetHTTPHeader
		(
			int ソケットファイルディスクリプタ , char *データを格納する文字型配列 ,
			int 文字型配列の長さ , int 最大何行取得するか
		)
	
	return 0 http形式のヘッダーを正確に取得できた
	return 1 受信の途中で接続が切れた
	return 2 ヘッダの最大受信行数に達した
	return 3 初期化された文字配列の長さを超えそうになった

	*補足*
	HTTPヘッダ形式(\r\nで区切られた)のヘッダを受信しptrに書き込みます
	-----------------------------------------------------------------------
*/

int tcpGetHTTPHeader(int sockfd  , char *ptr , int ptrsize , int maxline){
	
	int flag = 0;
	int line = 0;
	int justrecvedsize = 0;
	int ptraxcel = 0;

	for(ptraxcel = 0;ptraxcel<ptrsize;ptraxcel++){
		
		justrecvedsize = recv(sockfd , ptr+ptraxcel , 1 , 0);
		
		if (justrecvedsize == 0)
				return 1;
		if ((*(ptr+ptraxcel) == '\r') || (*(ptr+ptraxcel) == '\n') ){
				flag += 1;
				if (flag == 4){ 
					return 0;
				}else if(flag == 2){
					line += 1;
				}
				if (line == maxline)
						return 2;
		}else{
			flag = 0;
		}
		
	}
	return 3;
}


comment 0 trackback 0
05.26
Sat
こんちは

TCPヘッダやらIPヘッダにくっつけるチェックサムの事です。

いつもそうなんですが、今回の記事はいつもよりまして嘘を書いてる可能性があるので、

あくまで参考程度に。若しくは見ないことをお勧めします。

まずチェックサムの出し方。単刀直入に言うと1の補数和の1の補数。

補数とか言葉の定義とかいろいろその辺りはめんどくさいので、

求め方をC言語を使ったとして単純に書きますが、


1.まず構造体で各ヘッダを作る。

2.構造体の各値を足し算して、16bitを溢れた値を最下位ビットに足し算していく

3.最後にビットを反転させる ~sumみたいな感じ

それを自分なりに書いてみました

unsigned short int mychecksum(unsigned short int *ptr , int size)
{
	int index = 0;
	int sum = 0;
	int carry = 0;
	for (index = 0;index<size ; index++)
	{
		sum += *(ptr+index);		
		if (sum > 0x0000FFFF)
		{
		         carry = sum >> 16;
			sum = (sum & 0x0000FFFF) + carry;

		}
	}
	return (unsigned short int)~sum;
}


・まず*ptrに対象の構造体の先頭ポインタを渡す.


・ループの中でポインタにindexを足し算することで
 次の値次の値...を参照するようになるそれをsizeまで行いsumに足していく


・*ptrはshort型なのでindexを足すと2byte = 16bit = 2octet進む


・sumに足してる間に桁溢れが生じたら、その溢れた値を最下位ビットに足し込む。
 桁が溢れるということは(16bit以上になるということは)
 今int型でsumを宣言してるので、sumが0x0000FFFF以上になるということなので
 それを条件判断に使ってる


・16進数の1桁の重みは2進数の4桁分なので、キャリを求めるには
 右に16ビットシフトさせる。イメージ図はこんな感じ↓
checksum.png


・で、最後に
 新しいsumをsumと0x0000FFFFとのAND演算の結果 + キャリとするんだけど
 AND演算を行う理由は桁上りが残ってる上位16ビットを消すためにする。
 キャリを足す理由はそもそも1の補数和だから。



これでやっとチェックサムを求める関数が書けた。と思う。たぶん。三割くらいの確率であってると思う←

次のブログのネタはこの関数でどこの部分のチェックサムを求めればいいのかのメモをしてみる

TCPのチェックサムを求めるのに疑似ヘッダが必要になってくるので

では最後に,上記の関数を用いたわかりやすい例を書いておきます。

#include <stdio.h>


unsigned short int checksum(unsigned short int *ptr , int size)
{
	int index = 0;
	int sum = 0;
	int carry = 0;
	for (index = 0; index<size; index++)
	{
		sum += *(ptr+index);		
		if (sum > 0x0000FFFF)
		{
		         carry = sum >> 16;
			sum = (sum & 0x0000FFFF) + carry;

		}
	}
	return (unsigned short int)~sum;
}


int main(void)
{
	
	unsigned short int arry[] = {
		0x1234 ,
		0xabcd ,
		0x4321 ,
		0xdcba ,
		0xffab ,
		0xed21 ,
	};

	printf("CHECK SUM = %x\n" , checksum(arry , sizeof(arry)/sizeof(arry[0])));



	return 0;
}


手計算で

0x1234 + 0xabcd + 0x4321 + 0xdcba + 0xffab + 0xed21

をやって、

多分0x3cca8になるので

0xcca8 + 0x3をして

それを否定すれば同じ結果になるはずです
comment 0 trackback 0
05.20
Sun
さてー、タイトルの通りSYNパケットを送ってみます。

まず、SYNパケットとは何かについて書きます。


SYNパケットというのはトランスポート層のプロトコルであるTCPが使う

SYNフラグの立った特殊なパケットのことです(セグメントって言うべきなのかな)

TCPというプロトコルはUDPと違って信頼性があります。

なので、通信の初めに通信相手と仮想的なコネクションを張るのですが

その制御のために使われるのがSYNパケットです

まず通信したい側がこのSYNパケットを送って

これから接続したいんだけどー的な旨を伝えます

そうすると、接続される側(サーバ)は接続のための準備に入ります

具体的にはここでサーバはいろいろリソースをクライアントのために割り当てます。

そんで、サーバはクライアントにSYN,ACKパケットを返して

接続に来ておっけーだよーって言います

おっけーじゃないときはRSTフラグの立ったパケットが返ると思います。

そして最後にクライアントがACKを送信することで接続が完了します.

3段階を踏んでいるので、これをスリーウェイハンドシェイクって言います

ということで、以下のコードはその一番最初のSYNを送るものです.

普通この接続処理はconnect()とかがやってくれているはずですが、

生ソケットを使ったりすると、この辺の実装から行えるわけです。

本当はもっと低レイヤのプロトコルのヘッダからいじれるのですが、

私の技量不足等により今回はTCPあたりを。

このコードの説明とかはいつかのブログのネタにとっておきますw

特にチェックサムあたりのめんどい部分は忘れてしまいそうなので。


動作環境はUbuntuです

このコードはループバックアドレス127.0.0.1のポート12345から

127.0.0.1のポート80へSYNパケットを送信します



#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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


struct dummyIPheader{
	
	unsigned int srcIP;
	unsigned int dstIP;
	unsigned char zero;
	unsigned char protocol;
	unsigned short len;
	
};

struct dummyHeader {
	struct dummyIPheader pIPheader;
	struct tcphdr pTCPheader;
};

unsigned short checksum(unsigned short *ptr , int size);

int main(void)
{
	
	struct tcphdr TCPheader;
	struct dummyHeader pHeader;
	struct sockaddr_in peer;
	int sock;
	int srcport = 12345;
	int dstport = 80;
	int windowsize = 512;
	char srcip[] = "127.0.0.1";
	char dstip[] = "127.0.0.1";
	
	TCPheader.source = htons(srcport);
	TCPheader.dest = htons(dstport);
	TCPheader.seq = 1;
	TCPheader.window = htons(windowsize);
	TCPheader.fin = 0;
	TCPheader.syn = 1;
	TCPheader.doff = 5;
	TCPheader.rst = 0;
	TCPheader.urg = 0;
	TCPheader.urg_ptr = 0;
	TCPheader.psh = 0;
	TCPheader.ack_seq = 0;
	TCPheader.ack = 0;
	TCPheader.check = 0;
	TCPheader.res1 = 0;
	TCPheader.res2 = 0;
	
	inet_aton(srcip , &pHeader.pIPheader.srcIP);
	inet_aton(dstip , &pHeader.pIPheader.dstIP);
	pHeader.pIPheader.zero = 0;
	pHeader.pIPheader.protocol = 6;
	pHeader.pIPheader.len = htons(20);	

		
	inet_aton(dstip , &peer.sin_addr);
	peer.sin_port = htons(dstport);
	peer.sin_family = AF_INET;

	bcopy((char *)&TCPheader , (char *)&pHeader.pTCPheader , 20);

	TCPheader.check = checksum((unsigned short *)&pHeader , 32);

	sock = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);

	if (sock < 0 ){
		perror("socket");
		return 1;
	}
	
	if (sendto(sock , &TCPheader , sizeof(TCPheader) , 0 , (struct sockaddr *)&peer , sizeof(peer)) <0 ){
		perror("sendto");
		close(sock);
		return 1;
	}

	close(sock);
	return 0;
}
unsigned short checksum(unsigned short *ptr , int size)  
{  
    int index = 0;  
    int sum = 0;  
    short int proc = 0;  
  
    for (index = 0;index<size;index+=2){  
          
            sum += *(ptr++);  
    }  
  
    short int carry = sum >> 16;  
    
    short int main = 0x0000ffff & sum;
    
    short int result = ~(main+carry);  
  
    return result;  
}  


comment 0 trackback 0
back-to-top
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。