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

07.05
Fri
ということでタイトル通り、FFIでLispから共有ライブラリを使ってみます

てかFFIってCommonLisp由来の用語だったんですね。恥ずかしながら知りませんでした

さて、FFIで他言語の機能を利用してみようというわけですが

今回はCで書いてたrawsocket関連のやつを呼んでみます。

CLにはFFIにもいろいろ種類があって、処理系に依存しないCFFIなんかは有名なんですが

CFFIだとCの構造体の値渡しができなかったり、
(cffi-libffi入れればできるらしいけどうまく環境作れなかった)

移植性は高いけど、処理系依存の方法に機能的には劣るので、SBCL依存の方法で書いてみました

SBCLのFFIに関するリンクを貼っときます

Foreign Function Interface

ということで元のCのソースを貼ります

#include <stdio.h>

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


#define __FAVOR_BSD
#include <netinet/tcp.h>
#include <arpa/inet.h>


//#define MSS 1460


typedef struct {
	struct tcphdr tcp_h;
	//unsigned char data[MSS];
}TCP_Segment;

typedef struct {
	struct in_addr src_addr;
	struct in_addr dst_addr;
	unsigned char zero;
	unsigned proto;
	unsigned short int length;
}pIP_h;

typedef struct {
	pIP_h        pip_h;
	TCP_Segment  tcp_seg;
}pPacket;


void setTCP_h(
		struct tcphdr          *ptr , 
		unsigned short int th_sport , 
		unsigned short int th_dport , 
		unsigned int         th_seq , 
		unsigned int         th_ack , 
		unsigned char        th_off , 
		unsigned char      th_flags , 
		unsigned short int   th_win , 
		unsigned short int   th_sum , 
		unsigned short int   th_urp  
		){
	
	ptr->th_sport = htons(th_sport);
	ptr->th_dport = htons(th_dport);
	ptr->th_seq   = htonl(th_seq);
	ptr->th_ack   = htonl(th_ack);
	ptr->th_off   = th_off;
	ptr->th_flags = th_flags;
	ptr->th_win   = htons(th_win);
    ptr->th_sum   = th_sum;
	ptr->th_urp   = th_urp;	
	ptr->th_x2    = 0;
}


unsigned short checksum(unsigned short *ptr , int size){
	int sum   = 0x00000000;
	int carry = 0x00000000;
	int index;

	for(index = 0; index < size ; index++){
		sum += *(ptr+index);
		if (sum > 0x0000FFFF){
			carry = sum >> 16;
			sum   = (sum & 0x0000FFFF) + carry;
		}
	}

	return (unsigned short)~sum;
}





void makerst(
		pPacket *ptr , 
		char *srcip  , 
		char *dstip  ,
		unsigned short srcport  ,
		unsigned short dstport  
		){

	inet_aton(srcip , &ptr->pip_h.src_addr);
	inet_aton(dstip , &ptr->pip_h.dst_addr);

	ptr->pip_h.zero   =  0;
	ptr->pip_h.proto  =  6;
	ptr->pip_h.length = 20;

	/* RSTフラグの立ったパケットを送るだけなので 
	 * データは無いので、20
	 */

	setTCP_h
		(
		 &ptr->tcp_seg.tcp_h ,
		 srcport             ,
		 dstport             ,
		 12345               , /* SEQの値 */
		 0                   , /* ACKの値 */
		 5                   , /* どこから始まるか */
		 0x04                , /* RSTフラグは0x04 */
		 8192                , /* windowサイズ */
		 0                   ,
		 0);

	unsigned short sum = checksum((unsigned short *)&ptr , sizeof(*ptr));
	ptr->tcp_seg.tcp_h.th_sum = sum;

}

void setaddr_in(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);
}


int sendrst(char *srcip , char *dstip , unsigned short srcport , unsigned short dstport)
{
	struct sockaddr_in dst;
	pPacket packet;
	int s = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);

	if (s < 0 ) return -1;

	setaddr_in(&dst , dstip , dstport);
	makerst(&packet , srcip , dstip , srcport , dstport);

	/* TCPヘッダだけなので20 */
	if (sendto(s , (char *)&packet.tcp_seg , 20 , 0 , (struct sockaddr *)&dst , sizeof(dst)) < 0){
		close(s);
		return -2;
	}
	close(s);
	return 0;	
}


何をするかというと、RSTフラグの立ったTCPヘッダを作って

適当なホストに投げるというもの

でこれから共有ライブラリを作ります

gcc -fpic -c rawsock.c
gcc -shared -o librawsock.so rawsock.o


で呼び出す側のLispのコード



(load-shared-object "./librawsock.so")


(define-alien-routine sendrst int 
    (srcip c-string) 
    (dstip c-string)
    (srcport int)
    (dstport int))


(format t "Result of sendrst ~A~%" (sendrst "127.0.0.1" "127.0.0.1" 12345 54321))


こいつに権限を与えて実行すると

sendrst.png

うまくRSTの立ったパケットが流れたようです
スポンサーサイト

comment 0 trackback 0
トラックバックURL
http://telracsmoratori.blog.fc2.com/tb.php/174-dd884735
トラックバック
コメント
管理者にだけ表示を許可する
 
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。