libipq 관련 질문입니다.

jjangiya의 이미지

간단한 샘플코드를 통해 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 화이팅입니다.

mach의 이미지

netfilter프레임워크의 커널모듈들이 로딩되었는지 검토하세요.
# modprobe iptable_filter
# modprobe ip_queue <==== 이 커널모듈이 필수적으로 올라와야함 모듈관리유틸리티참조
************ 터미널 하나를 띄워서 ping 을 실행시켜둔다.
# iptables -A OUTPUT -p icmp -j QUEUE <==== icmp패킷을 QUEUE로 보냄
************ 이 룰이 올라오는 순간 OUTPUT에서 후킹된 패킷중 icmp패킷은 QUEUE로 보내진다.
************ 만일 유저영역에서 받아주는/보내는 프로그램이 없다면, 패킷은 드랍된다.
# 위에서 작성한 예제를 실행한다.

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

jjangiya의 이미지

모듈은 insert 시켰는데두, 그러네요.. 또 다른 iptables에 관련된
모듈도 올려야 하나요?

감사합니다.

wfellow의 이미지

이런 이야기 하긴 뭐하지만,.. ipq에 대한 내용을 찾아 보셨는지 모르겠네요. 에궁..
ipq는 커널내에서 패킷을 잡아서리 그 패킷의 상태를 NF_ACCEPT, NF_DROP가 아닌 NF_QUEUE로
만들어야 외부 어플리케이션에서 잡아가져.

구글링을 더 해 보시던지, 아님 ip_queue.{c|h}를 좀 더 분석을 하시던지 하셔야 할줄로 아뢰오~~
휘리릭 =3=3=3

-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----

-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----

mach의 이미지

# 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. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

jjangiya의 이미지

답변 해주신 여러분께 진심으로 감사합니다.

iptables 에서 queue로 보내야만 패킷을 잡을수 있는거군요. ㅋㅋ

예 감사합니다. ^^

jjangiya의 이미지

libipq를 써서 패킷의 ip헤더나 tcp헤더등의 내용들을 받을수 있나요?

ipq_packet_message 의 내용을 보니까 맥어드레스나 패킷의 길이 아이디등의
내용은 있는데, ip나 tcp헤더와 관련된 내용은 없어 보이네요..

주소라든가 포트는 알수 없나요?

mach의 이미지

당연히 패킷정보를 모두 얻을 수 있습니다.
그외 메타정보( 기타 부가정보라 합시다 ) 또한 얻을 수 있습니다.

아래 예제는 구글에서 무려 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. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.