recvfrom 에서 block 현상에 대해 다시 질문 드리겠습니다.

kphwan의 이미지

안녕하세요
아래 질문을 드렸었는데..
다시 새로 질문을 드리겠습니다.

A(발신지-리눅스)와 B(수신지-윈도우) 호스트 각각에 패킷 캡쳐 프로그램을 실행시켜 놓구요
A 지점에서 SYN 플래그를 실은 패킷을 sendto 보내고
recvfrom 으로 패킷이 오는것을 대기 하도록 소스가 짜여져 있습니다.

이 프로그램을 수신지에서 실행시켜 놓고
패킷캡쳐화면을 분석하면 다음과 같이 나옵니다.
SYN -> SYN,ACK -> ACK

수신지와 발신지에서 모두 위와 같이 캡쳐화면에서 3-way handshake 가 발견되었습니다.

그런데 유독 이상하게
리눅스 터널에서 실행시켜 놓은 프로그램에서는
recvfrom 함수에서 딱 block 이 되어 다음으로 넘어가질 않더라구요...

왜 그런건가요???
조언 부탁드리겠습니다.

소스도 함께 첨부하겠습니다.
소스는 hackerschool 에서 따와서 약간 응용을 하였기에
원본 소스 그대로 올려놓겠습니다.

// 필요한 헤더들 선언

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

// 발신자의 IP 주소, 컴파일 전에 수정하세요.

#define LOCAL_IP “218.149.4.173”

// 체크섬을 구하는 함수 선언/정의.

unsigned short in_cksum(u_short *addr, int len)

{

int sum=0;

int nleft=len;

u_short *w=addr;

u_short answer=0;

while (nleft > 1){

sum += *w++;

nleft -= 2;

}

if (nleft == 1){

*(u_char *)(&answer) = *(u_char *)w ;

sum += answer;

}

sum = (sum >> 16) + (sum & 0xffff);

sum += (sum >> 16);

answer = ~sum;

return(answer);

}

// 가상 헤더 구조체 선언

struct pseudohdr {

u_int32_t saddr;

u_int32_t daddr;

u_int8_t useless;

u_int8_t protocol;

u_int16_t tcplength;

};

int main( int argc, char **argv )

{

unsigned char packet[40];

int raw_socket, recv_socket;

int on=1, len ;

char recv_packet[100], compare[100];

struct iphdr *iphdr;

struct tcphdr *tcphdr;

struct in_addr source_address, dest_address;

struct sockaddr_in address, target_addr;

struct pseudohdr *pseudo_header;

struct in_addr ip;

struct hostent *target;

int port;

if( argc < 2 ){

fprintf( stderr, "Usage : %s Target\n", argv[0] );

exit(1);

}

source_address.s_addr = inet_addr( LOCAL_IP );

dest_address.s_addr = inet_addr( argv[1] );

strcpy( compare, argv[1] );

// 인자로 도메인을 주었을 경우 IP로 변환.

if( dest_address.s_addr == -1 ){

if( (target = gethostbyname( argv[1] )) == NULL ){

fprintf( stderr, "도메인 주소가 올바르지 않습니다.\n" );

exit( 1 );

}

bcopy( target->h_addr, (char *)&ip.s_addr, target->h_length );

dest_address.s_addr = ip.s_addr;

strcpy( compare, inet_ntoa( dest_address ) );

}

printf( "\n[Wise Scanner Started.]\n\n" );

// 1번에서부터 500번까지 스캔

for( port=1; port<500; port++ ){

// raw socket 생성

raw_socket = socket( AF_INET, SOCK_RAW, IPPROTO_RAW );

setsockopt( raw_socket, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on));

// TCP, IP 헤더 초기화

iphdr = (struct iphdr *)packet;

memset( (char *)iphdr, 0, 20 );

tcphdr = (struct tcphdr *)(packet + 20 );

memset( (char *)tcphdr, 0, 20 );

// TCP 헤더 제작

tcphdr->source = htons( 777 );

tcphdr->dest = htons( port );

tcphdr->seq = htonl( 92929292 );

tcphdr->ack_seq = htonl( 12121212 );

tcphdr->doff = 5;

tcphdr->syn = 1;

tcphdr->window = htons( 512 );

// 가상 헤더 생성.

pseudo_header =

(struct pseudohdr *)((char*)tcphdr-sizeof(struct pseudohdr));

pseudo_header->saddr = source_address.s_addr;

pseudo_header->daddr = dest_address.s_addr;

pseudo_header->protocol = IPPROTO_TCP;

pseudo_header->tcplength = htons( sizeof(struct tcphdr) );

// TCP 체크섬 계산.

tcphdr->check = in_cksum( (u_short *)pseudo_header,

sizeof(struct pseudohdr) + sizeof(struct tcphdr) );

// IP 헤더 제작

iphdr->version = 4;

iphdr->ihl = 5;

iphdr->protocol = IPPROTO_TCP;

iphdr->tot_len = 40;

iphdr->id = htons( 12345 );

iphdr->ttl = 60;

iphdr->saddr = source_address.s_addr;

iphdr->daddr = dest_address.s_addr;

// IP 체크섬 계산.

iphdr->check = in_cksum( (u_short *)iphdr, sizeof(struct iphdr));

address.sin_family = AF_INET;

address.sin_port = htons( port );

address.sin_addr.s_addr = dest_address.s_addr;

// 패킷 전송

sendto( raw_socket, &packet, sizeof(packet), 0x0,

(struct sockaddr *)&address, sizeof(address));

// 응답 패킷의 헤더를 저장할 변수 초기화.

iphdr = (struct iphdr *)recv_packet;

tcphdr = (struct tcphdr *)(recv_packet + 20);

memset( (char *)iphdr, 0, 20 );

memset( (char *)tcphdr, 0, 20 );

// 수신용 패킷 생성

recv_socket = socket( AF_INET, SOCK_RAW, IPPROTO_TCP );

len = sizeof( target_addr );

// 응답 패킷 검출

while(1){

recvfrom( recv_socket, recv_packet, 100, 0,

(struct sockaddr *)&target_addr, &len );

if( strcmp( inet_ntoa(target_addr.sin_addr), compare ) == 0 ){

if( ntohs(tcphdr->dest) == 777 ){

// syn 플래그 설정 여부 확인

if( tcphdr->syn == 1 )

printf( "%d Port is open.\n", port );

break;

}

}

}

close( recv_socket );

close( raw_socket );

}

printf( "\n[Scan ended.]\n\n" );

}

mirr187의 이미지

제 경험으로 봤을 때 recv 에서 block 되는 경우는 사이즈의 문제일 경우가 대부분이었습니다.

위의 코드로 봤을 때 100bytes 를 recv 하는걸로 하셨는데, return 값을 체크하실 필요가 있을것으로 보입니다.

100bytes 를 recv 하지 못하였을 때 block 되는 경우가 발생할 수 있습니다.

kphwan의 이미지

그래서 recv_packet 의 사이즈를 1000 으로 늘려보았습니다.
그래도 block 이 걸리더라구요..

그런데 코드를 보면 조금의 의문점이 생기는 데요

for(port = 1 ; port < 500 ; port++){
while(1){
recvfrom();
if(tcp->dest == 777) {
printf("%d port open ", port);
break;
}
}
}

간단히 보면 while 문이 계속 돌아가는 것 처럼 보이네요...
이 상황에서 어떻게 port 가 증가가 되는 건가요??
port 가 1인 상황에서 if문에의해 port 체크가 false 가 되는 상황이 끊임없이 반복되는 듯 보입니다.

여기저기서 찾아보고는 있지만 쉽지가 않습니다.
조언 부탁드리겠습니다.

mirr187의 이미지

사용중인 장비가 linux와 윈도우라고 하셨는데.. linux쪽 장비에서 문제가 발생하였다고 가정하였을 경우 strace 라는 system call을 trace하는 tool을 사용하셔서 recvfrom 호출시 어떤식으로 동작하는지 확인해보시는게 좋을 거 같습니다..

일단.. 제가 얘기드린 부분에서 오해가 있는거 같은데.. 다시 한번 얘기드리면 다음과 같습니다.

send 하는 쪽에서 100을 보내야 하는데, 실제로 90을 보냈다면
recv 하는 쪽에서 90을 받고 끝내게 되어 있지 않는거 같습니다... 100을 받을때까지 loop를 돌게 되어 있는거 같다는 이야기입니다...

위에서

while(1){

recvfrom( recv_socket, recv_packet, 100, 0,

(struct sockaddr *)&target_addr, &len );
}

하는 부분에서 100이라는 사이즈를 고정해서 받게끔 하셨는데.. 정말로 제대로 받고 있는지 return 값을 체크하셔서 확인하시는게 좋을 거 같습니다..

만약 위에서 언급한 사이즈 문제가 아닐수도 있으니, strace를 사용하셔서 모니터링 해보시는 것을 추천드립니다. ^^;

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.