libipq 관련 질문입니다.
글쓴이: jjangiya / 작성시간: 화, 2006/06/27 - 3:37오후
간단한 샘플코드를 통해 libipq가 동작하려는것을 보려고 하는데요.
일단 소스코드입니다.
/*
* This code is GPL.
*/
#include <linux/netfilter.h>
#include <libipq/libipq.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define BUFSIZE 2048
static int die(struct ipq_handle *h)
{
ipq_perror("passer");
ipq_destroy_handle(h);
exit(0);
}
int main(int argc, char **argv)
{
int status;
unsigned char buf[BUFSIZE];
struct ipq_handle *h;
h = ipq_create_handle(0, PF_INET);
if (!h)
die(h);
status = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE);
if (status < 0)
{
printf("error point\n");
die(h);
}
do{
status = ipq_read(h, buf, BUFSIZE, 0);
if (status < 0)
die(h);
switch (ipq_message_type(buf)) {
case NLMSG_ERROR:
fprintf(stderr, "Received error message %d\n",
ipq_get_msgerr(buf));
break;
case IPQM_PACKET: {
ipq_packet_msg_t *m = ipq_get_packet(buf);
status = ipq_set_verdict(h, m->packet_id,
NF_DROP, 0, NULL);
if (status < 0)
die(h);
break;
}
default:
fprintf(stderr, "Unknown message type!\n");
break;
}
} while (1);
ipq_destroy_handle(h);
return 0;
} 위의 소스코드에서 ipq_read() 함수를 통해서 패킷을 읽어오는것 같은데요..
ipq_read() 함수에서 더이상 진행이 되질 않네요.. 그러니까 ipq_read함수에서 리턴이 되질 않고 뭔가를
계속 기다리는것 같은데...
혹시 아시는분 계시면 답변해 주시면 정말 감사하겠습니다.
kldp 화이팅입니다.
Forums:


netfilter프레임워크의
netfilter프레임워크의 커널모듈들이 로딩되었는지 검토하세요.
# modprobe iptable_filter
# modprobe ip_queue <==== 이 커널모듈이 필수적으로 올라와야함 모듈관리유틸리티참조
************ 터미널 하나를 띄워서 ping 을 실행시켜둔다.
# iptables -A OUTPUT -p icmp -j QUEUE <==== icmp패킷을 QUEUE로 보냄
************ 이 룰이 올라오는 순간 OUTPUT에서 후킹된 패킷중 icmp패킷은 QUEUE로 보내진다.
************ 만일 유저영역에서 받아주는/보내는 프로그램이 없다면, 패킷은 드랍된다.
# 위에서 작성한 예제를 실행한다.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
예 두 모듈은 전부 올라와 있는상태이구요 ^^
모듈은 insert 시켰는데두, 그러네요.. 또 다른 iptables에 관련된
모듈도 올려야 하나요?
감사합니다.
이런 이야기 하긴 뭐하지만,,,
이런 이야기 하긴 뭐하지만,.. ipq에 대한 내용을 찾아 보셨는지 모르겠네요. 에궁..
ipq는 커널내에서 패킷을 잡아서리 그 패킷의 상태를 NF_ACCEPT, NF_DROP가 아닌 NF_QUEUE로
만들어야 외부 어플리케이션에서 잡아가져.
구글링을 더 해 보시던지, 아님 ip_queue.{c|h}를 좀 더 분석을 하시던지 하셔야 할줄로 아뢰오~~
휘리릭 =3=3=3
-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----
-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----
# iptables -A OUTPUT -p icmp
# iptables -A OUTPUT -p icmp -j QUEUE
처럼 iptables 유틸리티를 이용해서 룰을 기술해 주어야 합니다.
타겟은 위에서 보시다시피 QUEUE로 가게 하지요. ( -j QUEUE 부분)
iptables유틸리티는 특정 유형의 패킷에 대한 제어를 기술할 수 있습니다.
리눅스 방화벽에서는 차단등을 구현할때 사용합니다. 그외 NAT라던가 다양한 응용을 구현할 수 있습니다.
그런데, QUEUE에서 읽는 프로그램은 돌고 있는데(libipq를 이용한 프로그램) 이 QUEUE로 데이터를 보내는 것이 없다면 질문자님처럼 멈춰있겠지요?
1) iptables유틸리티로 특정 패킷을 QUEUE로 가도록 룰을 기술한다.
예) # iptables -A OUTPUT -p icmp -j QUEUE
2) 위 1)에서 기술한 특정 패킷을 발생시킨다.
예) # ping www.google.co.kr
3) 프로그램에서 이를 잘 ~ 잡는지 본다.
**위 예에서는 icmp패킷인 경우 OUTPUT인경우 QUEUE로 보내도록 룰을 기술했고, ICMP패킷을 발생시키기 위해 ping을 사용했다.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
아~
답변 해주신 여러분께 진심으로 감사합니다.
iptables 에서 queue로 보내야만 패킷을 잡을수 있는거군요. ㅋㅋ
예 감사합니다. ^^
하나만 더 질문해도 될까요..?
libipq를 써서 패킷의 ip헤더나 tcp헤더등의 내용들을 받을수 있나요?
ipq_packet_message 의 내용을 보니까 맥어드레스나 패킷의 길이 아이디등의
내용은 있는데, ip나 tcp헤더와 관련된 내용은 없어 보이네요..
주소라든가 포트는 알수 없나요?
당연히 패킷정보를
당연히 패킷정보를 모두 얻을 수 있습니다.
그외 메타정보( 기타 부가정보라 합시다 ) 또한 얻을 수 있습니다.
아래 예제는 구글에서 무려 3초만에 얻은 소스입니다(테스트는 해보지 않음)
#include <netinet/ip.h> 부분(및 tcp.h등도 참조)에서 ip헤더에 대한 선언을 이용하여, 얻은 데이터의 헤더부분을
건너뛰고, ip패킷인 경우에 ip헤더를 출력하는 예제로 보입니다.
아울러 tcp 헤더 정보나, 컨텐츠(애플리케이션 데이터)를 보려면 헤더를 잘~ 처리해야겠지요?
ip, tcp, udp, icmp등의 헤더정보 포맷을 잘 살펴보고 해당 패킷에 맞게 분석하면 되겠지요.
/* * ipq_client.c * * Simple ipq client for test & development. If you set dump_payload * to 1, you'll probably want to run as ./ipq_client > dump.out * * At the moment, this code grabs queued packets, mangles the TOS field, * then issues NF_ACCEPT verdicts. This is to establish that modifying * packets works. * * TODO: - Make more flexible, use getopts * - Add differential csum * - Add support for more protocols * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include <stdio.h> #include <netinet/in.h> #include <netinet/ip.h> #include <linux/netfilter.h> #include <unistd.h> #include "libipq.h" #define BUFSIZE 2048 static void die(struct ipq_handle *h); static void dump_metadata(ipq_packet_msg_t *m); static void dump_iphdr(unsigned char *buf); static u_int16_t csum_partial(void *buffer, unsigned int len, u_int16_t prevsum); int main(int argc, char **argv) { int status; unsigned char dump_payload = 0; unsigned char inbuf[BUFSIZE]; struct ipq_handle *h; int verdict = NF_ACCEPT; h = ipq_create_handle(0, PF_INET); if (!h) die(h); status = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE); if (status < 0) die(h); do { status = ipq_read(h, inbuf, BUFSIZE, 0); if (status < 0) die(h); switch (ipq_message_type(inbuf)) { case NLMSG_ERROR: fprintf(stderr, "Received error message %d\n", ipq_get_msgerr(inbuf)); break; case IPQM_PACKET: { ipq_packet_msg_t *m = ipq_get_packet(inbuf); unsigned char *packet = NULL; struct iphdr *iph = NULL; if (!m) break; dump_metadata(m); if (m->data_len >= sizeof(struct iphdr)) { packet = (unsigned char *)m + sizeof(*m); dump_iphdr(packet); } fprintf(stderr, "Sending verdict %d on " "packet %lX\n", verdict, m->packet_id); iph = (struct iphdr *)packet; iph->tos = 0x55; iph->check = 0; iph->check = ~csum_partial(packet, sizeof(struct iphdr), 0); status = ipq_set_verdict(h, m->packet_id, verdict, m->data_len, packet); if (status < 0) die(h); break; } default: fprintf(stderr, "Unknown message!\n"); break; } if (dump_payload) write(1, inbuf, status); } while (1); ipq_destroy_handle(h); return 0; } static void die(struct ipq_handle *h) { ipq_perror("ERROR"); ipq_destroy_handle(h); exit(1); } static void dump_metadata(ipq_packet_msg_t *m) { if(!m) return; fprintf(stderr, "Dumping Metadata:\nID=0x%08lX MARK=0x%08lX TSEC=%ld " "TUSEC=%ld HOOK=%u IN=%s OUT=%s DLEN=%d\n", m->packet_id, m->mark, m->timestamp_sec, m->timestamp_usec, m->hook, m->indev_name[0] ? m->indev_name : "[none]", m->outdev_name[0] ? m->outdev_name : "[none]", m->data_len); } /* * This does not handle IP options yet, although it may at some point * in the near future. Some of this code was stolen from ipt_LOG.c. */ static void dump_iphdr(unsigned char *buf) { struct iphdr *iph = (struct iphdr *)buf; fputs("Dumping IP Header:\n", stderr); fprintf(stderr, "VER=%u HLEN=%u TOS=0x%02hX TLEN=%u ID=%u ", iph->version, iph->ihl * 4, iph->tos, ntohs(iph->tot_len), ntohs(iph->id)); if (ntohs(iph->frag_off) & IP_DF) fputs("DF ", stderr); if (ntohs(iph->frag_off) & IP_MF) fputs("MF ", stderr); if (ntohs(iph->frag_off) & 0x1FFF) fprintf(stderr, "FRAG=%u ", (ntohs(iph->frag_off) & 0x1FFF) * 8); fprintf(stderr, "TTL=%u PROT=%u CSUM=0x%04X ", iph->ttl, iph->protocol, ntohs(iph->check)); fprintf(stderr, "SRC=%u.%u.%u.%u DST=%u.%u.%u.%u\n\n", (ntohl(iph->saddr) >> 24) & 0xFF, (ntohl(iph->saddr) >> 16) & 0xFF, (ntohl(iph->saddr) >> 8) & 0xFF, (ntohl(iph->saddr)) & 0xFF, (ntohl(iph->daddr) >> 24) & 0xFF, (ntohl(iph->daddr) >> 16) & 0xFF, (ntohl(iph->daddr) >> 8) & 0xFF, (ntohl(iph->daddr)) & 0xFF); } /* This is from gen_ip.c */ static u_int16_t csum_partial(void *buffer, unsigned int len, u_int16_t prevsum) { u_int32_t sum = 0; u_int16_t *ptr = buffer; while (len > 1) { sum += *ptr++; len -= 2; } if (len) { union { u_int8_t byte; u_int16_t wyde; } odd; odd.wyde = 0; odd.byte = *((u_int8_t *)ptr); sum += odd.wyde; } sum = (sum >> 16) + (sum & 0xFFFF); sum += prevsum; return (sum + (sum >> 16)); }------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
댓글 달기