- 참치군
- ?
- stalk.io
- :: 2013년, 스리는 여섯살
- 웹 강좌
- 점프 투 파이썬
- 요니나의 대학생 재테크
- This is CS50
- 애자일 이야기
- isao의 IT,게임번역소
- 소프트웨어 이야기
- Color Scripter
- 어디를 가든지 마음을 다해 가라
- VisuAlgo
- 서울대 평생교육원
- 몽환
- RegExr: Learn, Build, & Test R…
- Hello, Stranger :D
- I Like Exploit
- Z3alous Security Story
- Project Euler
- Blog
- pieces of code
- window 쪼물딱 거리기
- IT - Informatics Alphabet
- rop
- 국제 정보교육센터 I2sec 대구 1기
- This is the moment. :)
- blackmoon
- z3alous는 세상에 소리 z3alous~
- Acord
- FORENSIC-PROOF
- 어셈블리
- Outsider's Dev Story
- Open Tutorials
- 코드라이언
- 컴퓨터 그래픽스와 3D 프린팅
- HACKABILITY
- Lee, Jae-Hong
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 레지스터
- 컴파일러
- C언어
- 소켓
- Visual Studio
- Wireshark
- ubuntu
- Debug
- Hello World
- 베이스
- 염색
- 오지총
- Calling Convention
- 블루블랙
- 버퍼오버플로우
- Packet
- 디버깅
- 창의공학설계
- 공간복잡도
- 발표
- 호출규약
- BOF
- 동대구
- 파이썬
- 펌
- 추상데이터타입
- 탈색
- 피보나치
- 알고리즘
- 시간복잡도
- Today
- Total
c0smicb0y
netfilter library 본문
netfilter는 우리가 일반적으로 소켓 프로그래밍을 할 때 쓰이는 인터페이스인 Berkely socket interface의 외부에 존재하는 packet mangling에 대한 프레임워크이다.
쉽게 생각하여 일반적인 소켓 프로그래밍으로는 패킷을 모니터링하는 것은 가능하지만, 패킷을 변조, 드랍하는 것은 불가능하다. 이러한 것을 가능케 해주는 프레임워크가 netfilter이다.
netfilter는 크게 다섯 부분으로 구성되어 있으며, 각각의 프로토콜은 hook을 정의한다.
라우터로 들어오기 전인 PREROUTING
자기 자신으로 들어오는 LOCAL_IN
자기 자신에서 나가는 LOCAL_OUT
자기 자신이 라우터 역할을 하여 다른 곳으로 포워딩해주는 FORWARD
라우터를 지나 output interface로 포워드 된 패킷이 나간 후인 POSTROUTING
다섯 부분에 hook을 걸어서 패킷을 핸들링 할 수 있는데,핸들링의 종류는 다음과 같다.
NF_ACCEPT: 보통처럼 진행시킴
NF_DROP: 패킷을 버림 (소켓버퍼를 free함)
NF_STOLEN: 패킷을 훔침 (소켓버퍼를 free하지 않음)
NF_QUEUE: 패킷을 큐로 보냄 (userspace에서 처리하기 위해)
NF_REPEAT: 현재 훅을 다시 호출
netfilter 라이브러리를 사용하기 위해서는 먼저 모듈들을 다운로드 받아야 한다.
wget을 통해 다음 모듈들을 받아주자
1 | wget http://netfilter.org/projects/libmnl/files/libmnl-1.0.3.tar.bz2 |
1 | wget http://netfilter.org/projects/libnfnetlink/files/libnfnetlink-1.0.1.tar.bz2 | cs |
1 | wget http://netfilter.org/projects/libnetfilter_queue/files/libnetfilter_queue-1.0.2.tar.bz2 | cs |
http://netfilter.org 에서 각자 원하는 버전을 다운로드 받아주어도 된다.
우리가 원하는 기능은 netfilter_queue지만 dependency가 있어서 다른 모듈들을 먼저 설치해주어야 한다.
먼저 받은 압축파일들의 압축을 풀어준다.
1 | tar -xvf libmnl-1.0.3.tar.bz2 | cs |
1 | tar -xvf libnetfilter_queue-1.0.2.tar.bz2 | cs |
1 | tar -xvf libnfnetlink-1.0.1.tar.bz2 | cs |
각 디렉토리에 들어가서 빌드 및 설치를 한다.
1 2 3 4 | cd libmnl-1.0.3/ ./configure make sudo make install | cs |
1 2 3 4 | cd libnfnetlink-1.0.1/ ./configure make sudo make install | cs |
1 2 3 4 | cd libnetfilter_queue-1.0.2/ ./configure make sudo make install | cs |
설치는 libmnl -> libnfnetlink -> libnetfilter_queue의 순서대로 해야한다.
다음 예제 소스를 컴파일 해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <netinet/in.h> #include <linux/types.h> #include <linux/netfilter.h> /* for NF_ACCEPT */ #include <errno.h> #include <libnetfilter_queue/libnetfilter_queue.h> /* returns packet id */ static u_int32_t print_pkt (struct nfq_data *tb) { int id = 0; struct nfqnl_msg_packet_hdr *ph; struct nfqnl_msg_packet_hw *hwph; u_int32_t mark,ifi; int ret; unsigned char *data; ph = nfq_get_msg_packet_hdr(tb); if (ph) { id = ntohl(ph->packet_id); printf("hw_protocol=0x%04x hook=%u id=%u ", ntohs(ph->hw_protocol), ph->hook, id); } hwph = nfq_get_packet_hw(tb); if (hwph) { int i, hlen = ntohs(hwph->hw_addrlen); printf("hw_src_addr="); for (i = 0; i < hlen-1; i++) printf("%02x:", hwph->hw_addr[i]); printf("%02x ", hwph->hw_addr[hlen-1]); } mark = nfq_get_nfmark(tb); if (mark) printf("mark=%u ", mark); ifi = nfq_get_indev(tb); if (ifi) printf("indev=%u ", ifi); ifi = nfq_get_outdev(tb); if (ifi) printf("outdev=%u ", ifi); ifi = nfq_get_physindev(tb); if (ifi) printf("physindev=%u ", ifi); ifi = nfq_get_physoutdev(tb); if (ifi) printf("physoutdev=%u ", ifi); ret = nfq_get_payload(tb, &data); if (ret >= 0) printf("payload_len=%d ", ret); fputc('\n', stdout); return id; } static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) { u_int32_t id = print_pkt(nfa); printf("entering callback\n"); return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); } void dump(unsigned char*buf, size_t len) { size_t i; for (i = 0; i < len; i++) { printf("%02x ", *buf++); if ((i + 1) % 16 == 0) printf("\n"); } printf("\n"); fflush(stdout); } int main(int argc, char **argv) { struct nfq_handle *h; struct nfq_q_handle *qh; struct nfnl_handle *nh; int fd; int rv; char buf[4096] __attribute__ ((aligned)); printf("opening library handle\n"); h = nfq_open(); if (!h) { fprintf(stderr, "error during nfq_open()\n"); exit(1); } printf("unbinding existing nf_queue handler for AF_INET (if any)\n"); if (nfq_unbind_pf(h, AF_INET) < 0) { fprintf(stderr, "error during nfq_unbind_pf()\n"); exit(1); } printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n"); if (nfq_bind_pf(h, AF_INET) < 0) { fprintf(stderr, "error during nfq_bind_pf()\n"); exit(1); } printf("binding this socket to queue '0'\n"); qh = nfq_create_queue(h, 0, &cb, NULL); if (!qh) { fprintf(stderr, "error during nfq_create_queue()\n"); exit(1); } printf("setting copy_packet mode\n"); if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) { fprintf(stderr, "can't set packet_copy mode\n"); exit(1); } fd = nfq_fd(h); for (;;) { if ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0) { printf("pkt received\n"); dump(buf, rv); nfq_handle_packet(h, buf, rv); continue; } /* if your application is too slow to digest the packets that * are sent from kernel-space, the socket buffer that we use * to enqueue packets may fill up returning ENOBUFS. Depending * on your application, this error may be ignored. Please, see * the doxygen documentation of this library on how to improve * this situation. */ if (rv < 0 && errno == ENOBUFS) { printf("losing packets!\n"); continue; } perror("recv failed"); break; } printf("unbinding from queue 0\n"); nfq_destroy_queue(qh); #ifdef INSANE /* normally, applications SHOULD NOT issue this command, since * it detaches other programs/sockets from AF_INET, too ! */ printf("unbinding from AF_INET\n"); nfq_unbind_pf(h, AF_INET); #endif printf("closing library handle\n"); nfq_close(h); exit(0); } | cs |
컴파일 할 때 링크 옵션으로 -lnetfilter_queue를 주어야 한다.
실행을 시켜보면 so 파일이 없다는 에러가 뜰 것이다.
sudo su를 통해 root 권한으로 바꾼 후에,
1 | export LD_LIBRARY_PATH=/usr/local/lib; ./nfqnl_test | cs |
를 입력하면 실행이 된다.
해당 프로그램은 0번 큐에 들어오는 패킷들을 덤프를 떠서 보여주는 것이다.
iptables를 통해 0번 큐로 icmp를 보내주자.
1 | iptables -A OUTPUT -p icmp -j NFQUEUE --queue-num 0 | cs |
ping 8.8.8.8을 하면 해당 프로그램에서 포착될 것이다.