totofugaのブログ

ネットワークとかc言語、perlの話。

iptables勉強

ユーザ空間から IPTablesのチェインの取り出し。

とりあえずなんとなくとれるようになったので今日はここまで。

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <net/if.h>
#include <getopt.h>
#include <stdlib.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/x_tables.h>

int show_ipt_entry(struct ipt_entry * ent, struct ipt_getinfo *info, struct ipt_get_entries *entries) {
    struct xt_entry_target *xt_target = ipt_get_target(ent);

    // user定義チェイン
    if ( strcmp(xt_target->u.user.name, "ERROR") == 0 ) {
        printf("user定義チェイン(%s)\n", (char*)xt_target->data);
        return 0;
    }

    // builtinチェイン
    int i;
    for ( i = 0; i < NF_IP_NUMHOOKS; ++i ) {
        if ( info->valid_hooks & (1 << i) ) { // 有効か確認
            if ( (struct ipt_entry*)((char*)entries->entrytable + info->hook_entry[i]) == ent ) {
                switch( i ) {
                    case NF_IP_PRE_ROUTING:
                        printf("PREROUTING\n");
                        break;
                    case NF_IP_POST_ROUTING:
                        printf("POSTROUTING\n");
                        break;
                    case NF_IP_LOCAL_IN:
                        printf("LOACLIN\n");
                        break;
                    case NF_IP_LOCAL_OUT:
                        printf("LOCALOUT\n");
                        break;
                    case NF_IP_FORWARD:
                        printf("FORWARD\n");
                        break;
                    default:
                        printf("unknown chain\n");
                        break;
                }
            }
        }
    }

    struct xt_standard_target *st = (struct xt_standard_target*)xt_target;
    printf("#### ipt_verdict %d ####\n", st->verdict);

    return 0;
}

void main(int argc, char *argv[]) {

    char table[256] = {};
    strcpy(table, "filter");
    int arg;
    while( (arg = getopt(argc, argv, "t:")) != -1 ) {
        switch(arg) {
            case 't':
                strcpy(table, optarg);
                break;
        }
    }

    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);

    struct ipt_getinfo info;
    memset(&info, 0, sizeof(info));
    strcpy(info.name, table);


    int len = sizeof(info);
    if ( getsockopt(sock, IPPROTO_IP, IPT_SO_GET_INFO, &info, &len) == -1 ) {
        perror("IPT_SO_GET_INFO error\n");
        return;
    }

    printf("#### ipt_getinfo ####\n");
    printf("name : %s\n", info.name);
    printf("valid_hooks : %d\n", info.valid_hooks);
    printf("underflow: \n");
    printf("\tNF_INET_PRE_ROUTING : %d\n", info.underflow[NF_INET_PRE_ROUTING]);
    printf("\tNF_INET_LOCAL_IN: %d\n", info.underflow[NF_INET_LOCAL_IN]);
    printf("\tNF_INET_FORWARD: %d\n", info.underflow[NF_INET_FORWARD]);
    printf("\tNF_INET_LOCAL_OUT: %d\n", info.underflow[NF_INET_LOCAL_OUT]);
    printf("\tNF_INET_POST_ROUTING: %d\n", info.underflow[NF_INET_POST_ROUTING]);
    printf("num_entries: %d\n", info.num_entries);
    printf("size: %d\n", info.size);

    struct ipt_get_entries *entries;
    len = sizeof(*entries) + info.size;
    entries = calloc(1, len);
    strcpy(entries->name, info.name);
    entries->size = info.size;
    if ( getsockopt(sock, IPPROTO_IP, IPT_SO_GET_ENTRIES, entries, &len) == -1 ) {
        perror("IPT_SO_GET_ENTRIES error\n");
        return;
    }

    int i;
    for(i = 0; i < NF_INET_NUMHOOKS; ++i) {
        if ( info.underflow[i] == -1 ) {
            continue;
        }
        struct ipt_entry* ent = (struct ipt_entry*)((char*)entries->entrytable + info.underflow[i]);
        struct xt_entry_target *t = ipt_get_target(ent);
        if ( strcmp(t->u.user.name, "") != 0 ) {
            printf("error\n");
        }

        struct xt_standard_target *st = (struct xt_standard_target*)t;
    }

    IPT_ENTRY_ITERATE(entries->entrytable, entries->size, show_ipt_entry, &info, entries);

}