<ICMP(Internet Control Message Protocol)>
- ICMP는 TCP/IP에서 IP 패킷을 처리할 때 발생되는 문제를 알려주는 프로토콜이다.
- 우리 컴퓨터인 A에서 B컴퓨터의 상태를 보기위해 ping 을 찍으면 ICMP 프로토콜을 보내게 됩니다. 그렇게 되면 A 컴퓨터는 B의 네트워크 상태를 확인할 수 있습니다.
<IGMP(Internet Group Management Protocol)>
멀티캐스팅 데이터의 수신을 위해서 IGMP프로토콜을 사용한다. IGMP는 인터넷 그룹 관리 규약이라고 불린다.
아래 사이트에서 정보를 입수 블로그를 확인해보니 네트워크 기초지식을 보기좋게 정리해두었다. 공부용으로 좋은 것 같다.
TCP 패킷 - 4계층에서 사용되며 포트번호를 통해 데이터 전송
control bit에 값중 SYN 값이 1이고 ACK 값이 0이면 src에서 dst로 보내는 값을 나타내고
SYN 값과 ACK 값이 둘다 1이면 dst 에서 src로 SYN_ACK 패킷임을 나타낸다.
TCP 헤더의 체크섬은 Presudo(슈도) header와 TCP header 정보를 통해 만들어지게 된다.
<Raw 소켓으로 패킷 수신>
22~23 번째 줄을 보면 tcp 헤더와 IP 헤더를 설정하고 있는 것을 볼 수 있다.
row 소켓 모드에서 tcp 프로토콜을 사용하겠다는 것을30번째 줄을 통해서 확인할 수 있다.
39번째 줄에있는 recvfrom()메소드를 통해서 데이터를 읽어 드린다.
44~45번째 줄을 보면 tcp 헤더와 IP 헤더를 출력한다.
// read_packet.c
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <netinet/in.h>
#include <netdb.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
void print_ip(struct iphdr *);
void print_tcp(struct tcphdr *);
main( )
{
int sd;
int len;
int rx_packet_size = sizeof(struct iphdr) + sizeof(struct tcphdr);
char *rx_packet = malloc(rx_packet_size);
struct tcphdr *rx_tcph;
struct iphdr *rx_iph;
struct in_addr s_addr, d_addr;
struct sockaddr_in local, remote;
struct servent *serv;
if((sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
printf("socket open error\n");
exit(-1);
}
while(1) {
bzero(rx_packet, rx_packet_size);
len = sizeof(local);
if(recvfrom(sd,rx_packet,rx_packet_size,0x0,(struct sockaddr *)&local, &len)<0) {
printf("recvfrom error\n");
exit(-2);
}
rx_iph = (struct iphdr *)(rx_packet);
rx_tcph = (struct tcphdr *)(rx_packet + rx_iph->ihl * 4);
print_ip(rx_iph);
print_tcp(rx_tcph);
}
close(sd);
}
void
print_ip(struct iphdr *iph)
{
printf("[IP HEADER] VER: %1u HL : %2u Protocol : %3u ", iph->version, iph->ihl, iph->protocol);
printf("SRC IP: %15s ", inet_ntoa(*(struct in_addr *)&iph->saddr));
printf("DEST IP: %15s \n", inet_ntoa(*(struct in_addr *)&iph->daddr));
}
void
print_tcp(struct tcphdr *tcph)
{
printf("[TCP HEADER] src port: %5u dest port : %5u ", ntohs(tcph->source), ntohs(tcph->dest));
(tcph->urg == 1)?printf("U"):printf("-");
(tcph->ack == 1)?printf("A"):printf("-");
(tcph->psh == 1)?printf("P"):printf("-");
(tcph->rst == 1)?printf("R"):printf("-");
(tcph->syn == 1)?printf("S"):printf("-");
(tcph->fin == 1)?printf("F"):printf("-");
printf("\n\n");
}
IP 헤더를 프린트 하는 함수를 보면 IP 버전, IP 헤더 length, 프로토콜 종류와 도착, 출발 Ip 주소를 출력한다.
TCP 헤더를 프린트 하는 함수를 보면 출발지 포트번호와 도착지 포트 번호를 출력하며 컨트롤 비트들에 관해 출력한다.
무차별 모드라면 dst가 본인 아이피가 아니더라도 수집하게 될 것이다.
[IP HEADER] 버전, 헤더길이, src IP, dst IP
[TCP HEADER] src port, dest port, 컨트롤 비트
14~15번 줄을 보면 자신의 아이피 주소와 포트 번호를 설정하고 있다.
11~12번 줄을 보면 상대 서버의 스캔할 포트번호를 확인할 수 있다. 80~90 사이의 포트번호이다.
35번 째 줄을 통해서 명령어와 도메인 주소를 함깨 입력해야 함을 알 수 있다.
39번째 줄을 보면 도메인 주소를 target에 저장하고 있다.
48번째 줄을 보면 타켓 도메인 주소의 포트번호 80~90를 스캔하기 위해 반복문을 활용하고 있음을 확인할 수 있다.
scan_syn_port()함수를 살펴보겠다.
113~123번째 줄을 살펴보면 IP 헤더에 필요한 정보를 IP 헤더 구조체에 할당하고 있다.
123번째 줄은 체크섬을 만들고 있는 것을 확인할 수 있다.
130번째 줄에 sendto를 통해 원격지로 데이터를 전송한다. SYN 메시지를 전송하는 것이다.
141번째 줄에서 recvfrom을 통해서 SYN_ACK이 오길 기다린다.
147번째 줄과 149에서 상대방이 나에게 보낸 SYN_ACK인지 확인한다.
158번째에서 SYN값과 ACK 값을 확인한다.
위 이미지에서 체크섬에 관한 내용도 확인해 볼 수 있다.
위 실행 결과를 통해서 80번 포트 정보를 스캔하고있는 2번째 줄을 보면 마지막에 port[80] open/http를 확인할 수 있다.
이 데이터는 해당 포드에서 제공하는 서비스이다. 나머지 포트를 보면 *모양이 나타나있는 것을 확인할 수 있다. 이는 해당 포트는 열려있지 않다는 것이다.
위 정보는 SYN 패킷을직접 만들고 조정하고 SYN_ACK 패킷을 찾아내고 조사해서 얻은 결과라 할 수 있다.
scan_syn_port(unsigned long target, int port)
{
int sd;
int on = 1;
int len;
int tx_packet_size = sizeof(struct iphdr) + sizeof(struct tcphdr) + sizeof(struct pseudohdr);
int rx_packet_size = sizeof(struct iphdr) + sizeof(struct tcphdr);
char *rx_packet = (char *)malloc(rx_packet_size);
char *tx_packet = (char *)malloc(tx_packet_size);
struct tcphdr *tcph, *rx_tcph;
struct iphdr *iph, *rx_iph;
struct pseudohdr *pseudoh;
struct in_addr s_addr, d_addr;
struct sockaddr_in local, remote;
struct servent *serv;
iph = (struct iphdr *)(tx_packet);
tcph = (struct tcphdr *)(tx_packet + sizeof(struct iphdr));
pseudoh = (struct pseudohdr *)(tx_packet + sizeof(struct iphdr) + sizeof(struct tcphdr));
78
if((sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
printf("socket open error\n"); exit(-1);
}
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) {
printf("set socket option error\n"); exit(-2);
}
memset(tx_packet, 0, tx_packet_size);
d_addr.s_addr = target;
s_addr.s_addr = inet_addr(LOCAL_IP);
pseudoh->s_addr = s_addr.s_addr;
pseudoh->d_addr = d_addr.s_addr;
pseudoh->protocol = IPPROTO_TCP;
pseudoh->zero = 0;
pseudoh->length = htons(sizeof(struct tcphdr));
tcph->source = htons(LOCAL_PORT);
tcph->dest = htons(port);
tcph->seq = htons(random()%time(NULL));
tcph->ack_seq = 0;
tcph->doff = 5;
tcph->res1 = 0;
tcph->fin = 0;
tcph->syn = 1;
tcph->rst = 0;
tcph->psh = 0;
tcph->ack = 0;
tcph->urg = 0;
tcph->window = htons(1024);
tcph->check = (unsigned short)cksum_in((unsigned short *)tcph, (sizeof(struct tcphdr) + sizeof(struct pseudohdr)));
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = htons(tx_packet_size) - sizeof(struct pseudohdr);
iph->id = 0;
iph->frag_off = 0;
iph->ttl = IPDEFTTL;
iph->protocol = IPPROTO_TCP;
iph->saddr = s_addr.s_addr;
iph->daddr = d_addr.s_addr;
iph->check = (unsigned short)cksum_in((unsigned short *)iph, sizeof(struct iphdr));
remote.sin_family = PF_INET;
remote.sin_addr = d_addr;
remote.sin_port = htons(port);
remote.sin_port = 0;
if(sendto(sd, tx_packet, (tx_packet_size - sizeof(struct pseudohdr)), 0x0, (struct sockaddr *)&remote, sizeof(remote)) < 0) {
printf("send error\n"); exit(-3);
}
printf("[tx] %u->%u ", ntohs(tcph->source), ntohs(tcph->dest));
(tcph->urg == 1)?printf("U"):printf("-");
(tcph->ack == 1)?printf("A"):printf("-");
(tcph->psh == 1)?printf("P"):printf("-");
(tcph->rst == 1)?printf("R"):printf("-");
(tcph->syn == 1)?printf("S"):printf("-");
(tcph->fin == 1)?printf("F"):printf("-");
while(recvfrom(sd, rx_packet, rx_packet_size, 0x0, (struct sockaddr *)&local, &len) >0 ) {
rx_iph = (struct iphdr *)(rx_packet);
rx_tcph = (struct tcphdr *)(rx_packet + rx_iph->ihl * 4);
if( rx_iph->saddr != iph->daddr) continue;
if((ntohs(tcph->source) == ntohs(rx_tcph->dest)) && (ntohs(tcph->dest) == ntohs(rx_tcph->source))){
printf("[rx] %u->%u ", ntohs(rx_tcph->source), ntohs(rx_tcph->dest));
(rx_tcph->urg == 1)?printf("U"):printf("-");
(rx_tcph->ack == 1)?printf("A"):printf("-");
(rx_tcph->psh == 1)?printf("P"):printf("-");
(rx_tcph->rst == 1)?printf("R"):printf("-");
(rx_tcph->syn == 1)?printf("S"):printf("-");
(rx_tcph->fin == 1)?printf("F"):printf("-");
if(rx_tcph->syn == 1 && rx_tcph->ack == 1) {
serv = getservbyport(htons(port), "tcp");
printf(" port[%d] open/%s \n", ntohs(rx_tcph->source), serv->s_name);
} else if (rx_tcph->rst == 1) {
printf(" *\n");
} else {
printf("protocol error\n"); exit(-1);
}
break;
}
}
close(sd);
}
unsigned short
cksum_in(unsigned short *addr, int len)
{
unsigned long sum = 0;
unsigned short answer = 0;
unsigned short *w = addr;
int nleft = len;
while(nleft > 1) {
sum += *w++;
if(sum & 0x80000000)
sum = (sum & 0xffff) + (sum >> 16);
nleft -= 2;
}
if(nleft == 1) {
*(unsigned char *)(&answer) = *(unsigned char *)w;
sum += answer;
}
while(sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
return(sum==0xffff)?sum:~sum;
}
떳던 오류 관련
su에서 빠저나가는 방법 exit
https://storycompiler.tistory.com/44
---------------------------------------------------------------------------------------
<소스 port_scan_sys.c>
//syn_port_scan.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#define START_PORT 80
#define END_PORT 90
#define LOCAL_IP "203.249.39.141" // 자신의 IP 주소로 수정해야 함
#define LOCAL_PORT 9000 // 발신 포트 번호
unsigned short cksum_in(unsigned short *, int);
struct pseudohdr {
unsigned long s_addr;
unsigned long d_addr;
char zero;
unsigned char protocol;
unsigned short length;
};
main(int argc, char *argv[ ])
{
unsigned long target;
int portNum;
struct hostent *h;
if(argc < 2) {
printf("usage : portscan domain_name\n");
exit(-1);
}
if((target = inet_addr(argv[1])) == -1) {
h = gethostbyname(argv[1]);
if(!h) {
printf("gethostbyname error\n");
return 4;
}
target = ((struct in_addr*)h->h_addr)->s_addr;
}
for(portNum = START_PORT; portNum <= END_PORT; portNum++) {
printf("port %d scanning..", portNum);
scan_syn_port(target, portNum);
}
}
scan_syn_port(unsigned long target, int port)
{
int sd;
int on = 1;
int len;
int tx_packet_size = sizeof(struct iphdr) + sizeof(struct tcphdr) + sizeof(struct pseudohdr);
int rx_packet_size = sizeof(struct iphdr) + sizeof(struct tcphdr);
char *rx_packet = (char *)malloc(rx_packet_size);
char *tx_packet = (char *)malloc(tx_packet_size);
struct tcphdr *tcph, *rx_tcph;
struct iphdr *iph, *rx_iph;
struct pseudohdr *pseudoh;
struct in_addr s_addr, d_addr;
struct sockaddr_in local, remote;
struct servent *serv;
iph = (struct iphdr *)(tx_packet);
tcph = (struct tcphdr *)(tx_packet + sizeof(struct iphdr));
pseudoh = (struct pseudohdr *)(tx_packet + sizeof(struct iphdr) + sizeof(struct tcphdr));
78
if((sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
printf("socket open error\n"); exit(-1);
}
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) {
printf("set socket option error\n"); exit(-2);
}
memset(tx_packet, 0, tx_packet_size);
d_addr.s_addr = target;
s_addr.s_addr = inet_addr(LOCAL_IP);
pseudoh->s_addr = s_addr.s_addr;
pseudoh->d_addr = d_addr.s_addr;
pseudoh->protocol = IPPROTO_TCP;
pseudoh->zero = 0;
pseudoh->length = htons(sizeof(struct tcphdr));
tcph->source = htons(LOCAL_PORT);
tcph->dest = htons(port);
tcph->seq = htons(random()%time(NULL));
tcph->ack_seq = 0;
tcph->doff = 5;
tcph->res1 = 0;
tcph->fin = 0;
tcph->syn = 1;
tcph->rst = 0;
tcph->psh = 0;
tcph->ack = 0;
tcph->urg = 0;
tcph->window = htons(1024);
tcph->check = (unsigned short)cksum_in((unsigned short *)tcph, (sizeof(struct tcphdr) + sizeof(struct pseudohdr)));
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = htons(tx_packet_size) - sizeof(struct pseudohdr);
iph->id = 0;
iph->frag_off = 0;
iph->ttl = IPDEFTTL;
iph->protocol = IPPROTO_TCP;
iph->saddr = s_addr.s_addr;
iph->daddr = d_addr.s_addr;
iph->check = (unsigned short)cksum_in((unsigned short *)iph, sizeof(struct iphdr));
remote.sin_family = PF_INET;
remote.sin_addr = d_addr;
remote.sin_port = htons(port);
remote.sin_port = 0;
if(sendto(sd, tx_packet, (tx_packet_size - sizeof(struct pseudohdr)), 0x0, (struct sockaddr *)&remote, sizeof(remote)) < 0) {
printf("send error\n"); exit(-3);
}
printf("[tx] %u->%u ", ntohs(tcph->source), ntohs(tcph->dest));
(tcph->urg == 1)?printf("U"):printf("-");
(tcph->ack == 1)?printf("A"):printf("-");
(tcph->psh == 1)?printf("P"):printf("-");
(tcph->rst == 1)?printf("R"):printf("-");
(tcph->syn == 1)?printf("S"):printf("-");
(tcph->fin == 1)?printf("F"):printf("-");
while(recvfrom(sd, rx_packet, rx_packet_size, 0x0, (struct sockaddr *)&local, &len) >0 ) {
rx_iph = (struct iphdr *)(rx_packet);
rx_tcph = (struct tcphdr *)(rx_packet + rx_iph->ihl * 4);
if( rx_iph->saddr != iph->daddr) continue;
if((ntohs(tcph->source) == ntohs(rx_tcph->dest)) && (ntohs(tcph->dest) == ntohs(rx_tcph->source))){
printf("[rx] %u->%u ", ntohs(rx_tcph->source), ntohs(rx_tcph->dest));
(rx_tcph->urg == 1)?printf("U"):printf("-");
(rx_tcph->ack == 1)?printf("A"):printf("-");
(rx_tcph->psh == 1)?printf("P"):printf("-");
(rx_tcph->rst == 1)?printf("R"):printf("-");
(rx_tcph->syn == 1)?printf("S"):printf("-");
(rx_tcph->fin == 1)?printf("F"):printf("-");
if(rx_tcph->syn == 1 && rx_tcph->ack == 1) {
serv = getservbyport(htons(port), "tcp");
printf(" port[%d] open/%s \n", ntohs(rx_tcph->source), serv->s_name);
} else if (rx_tcph->rst == 1) {
printf(" *\n");
} else {
printf("protocol error\n"); exit(-1);
}
break;
}
}
close(sd);
}
unsigned short
cksum_in(unsigned short *addr, int len)
{
unsigned long sum = 0;
unsigned short answer = 0;
unsigned short *w = addr;
int nleft = len;
while(nleft > 1) {
sum += *w++;
if(sum & 0x80000000)
sum = (sum & 0xffff) + (sum >> 16);
nleft -= 2;
}
if(nleft == 1) {
*(unsigned char *)(&answer) = *(unsigned char *)w;
sum += answer;
}
while(sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
return(sum==0xffff)?sum:~sum;
}
</소스>
'네트워크' 카테고리의 다른 글
raw 소켓 #3 (0) | 2020.10.07 |
---|---|
raw 소켓 (0) | 2020.10.04 |
SFP(Small Form-factor Pluggable) Transceiver (0) | 2020.08.30 |
ARP(Address Resolution Protocol - 주소 결정 프로토콜) (0) | 2020.08.29 |
[c언어] 3바이트, 6바이트 데이터 타입 만들기 (0) | 2020.08.16 |