SOURCES (LINUX_2_6): iptables-nf-geoip.patch (NEW) - [extra] geoip...

cieciwa cieciwa at pld-linux.org
Thu Sep 15 09:36:11 CEST 2005


Author: cieciwa                      Date: Thu Sep 15 07:36:11 2005 GMT
Module: SOURCES                       Tag: LINUX_2_6
---- Log message:
- [extra] geoip - iptables patch.

---- Files affected:
SOURCES:
   iptables-nf-geoip.patch (NONE -> 1.1.2.1)  (NEW)

---- Diffs:

================================================================
Index: SOURCES/iptables-nf-geoip.patch
diff -u /dev/null SOURCES/iptables-nf-geoip.patch:1.1.2.1
--- /dev/null	Thu Sep 15 09:36:11 2005
+++ SOURCES/iptables-nf-geoip.patch	Thu Sep 15 09:36:05 2005
@@ -0,0 +1,373 @@
+ .geoip-test      |    3 
+ libipt_geoip.c   |  338 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ libipt_geoip.man |   15 ++
+ 3 files changed, 356 insertions(+)
+
+diff -Nur iptables.org/extensions/.geoip-test iptables/extensions/.geoip-test
+--- iptables.org/extensions/.geoip-test	1970-01-01 01:00:00.000000000 +0100
++++ iptables/extensions/.geoip-test	2005-09-15 09:20:28.000000000 +0200
+@@ -0,0 +1,3 @@
++#!/bin/sh
++# True if geoip is applied in given kernel tree.
++[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_geoip.h ] && echo geoip
+diff -Nur iptables.org/extensions/libipt_geoip.c iptables/extensions/libipt_geoip.c
+--- iptables.org/extensions/libipt_geoip.c	1970-01-01 01:00:00.000000000 +0100
++++ iptables/extensions/libipt_geoip.c	2005-09-15 09:20:28.000000000 +0200
+@@ -0,0 +1,338 @@
++/* Shared library add-on to iptables to add geoip match support.
++ 
++ * 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.
++ *
++ * Copyright (c) 2004 Cookinglinux
++ 
++ * For comments, bugs or suggestions, please contact
++ * Samuel Jean       <sjean at cookinglinux.org>
++ * Nicolas Bouliane  <nib at cookinglinux.org>
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <getopt.h>
++#include <ctype.h>
++#include <stddef.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <iptables.h>
++#include <linux/netfilter_ipv4/ipt_geoip.h>
++
++static void help(void)
++{
++   printf (
++            "GeoIP v%s options:\n"
++            "        [!]   --src-cc, --source-country country[,country,country,...]\n"
++            "                                                     Match packet coming from (one of)\n"
++            "                                                     the specified country(ies)\n"
++            "\n"
++            "        [!]   --dst-cc, --destination-country country[,country,country,...]\n"
++            "                                                     Match packet going to (one of)\n"
++            "                                                     the specified country(ies)\n"
++            "\n"
++            "           NOTE: The country is inputed by its ISO3166 code.\n"
++            "\n"
++            "\n", IPTABLES_VERSION
++         );
++}
++
++static struct option opts[] = {
++   {  "dst-cc",  1, 0, '2'  }, /* Alias for --destination-country */
++   {  "destination-country",   1, 0, '2'  },
++   {  "src-cc",  1, 0, '1'  }, /* Alias for --source-country */
++   {  "source-country",  1, 0, '1'  },
++   {  0  }
++};
++
++static void 
++init(struct ipt_entry_match *m, unsigned int *nfcache)
++{
++}
++
++/* NOT IMPLEMENTED YET
++static void geoip_free(struct geoip_info *oldmem)
++{
++}
++*/
++
++struct geoip_index {
++   u_int16_t cc;
++   u_int32_t offset;
++} __attribute__ ((packed));
++
++struct geoip_subnet *
++get_country_subnets(u_int16_t cc, u_int32_t *count)
++{
++   FILE *ixfd, *dbfd;
++   struct geoip_subnet *subnets;
++   struct geoip_index *index;
++   struct stat buf;
++  
++   size_t idxsz;
++   u_int16_t i;
++   
++   u_int16_t db_cc = 0;
++   u_int16_t db_nsubnets = 0;
++
++   if ((ixfd = fopen("/var/geoip/geoipdb.idx", "r")) == NULL) {
++         perror("/var/geoip/geoipdb.idx");
++         exit_error(OTHER_PROBLEM,
++               "geoip match: cannot open geoip's database index file");               
++   }
++   
++   stat("/var/geoip/geoipdb.idx", &buf);
++   idxsz = buf.st_size/sizeof(struct geoip_index);
++   index = (struct geoip_index *)malloc(buf.st_size);
++
++   fread(index, buf.st_size, 1, ixfd);
++
++   for (i = 0; i < idxsz; i++)
++      if (cc == index[i].cc)
++         break;
++   
++   if (cc != index[i].cc)
++      exit_error(OTHER_PROBLEM,
++            "geoip match: sorry, '%c%c' isn't in the database\n", COUNTRY(cc));
++
++   fclose(ixfd);
++
++   if ((dbfd = fopen("/var/geoip/geoipdb.bin", "r")) == NULL) {
++      perror("/var/geoip/geoipdb.bin");
++      exit_error(OTHER_PROBLEM,
++            "geoip match: cannot open geoip's database file");
++   }
++
++   fseek(dbfd, index[i].offset, SEEK_SET);
++   fread(&db_cc, sizeof(u_int16_t), 1, dbfd);
++
++   if (db_cc != cc)
++      exit_error(OTHER_PROBLEM,
++            "geoip match: this shouldn't happened, the database might be corrupted, or there's a bug.\n"
++            "you should contact maintainers");
++            
++   fread(&db_nsubnets, sizeof(u_int16_t), 1, dbfd);
++
++   subnets = (struct geoip_subnet*)malloc(db_nsubnets * sizeof(struct geoip_subnet));
++
++   if (!subnets)
++      exit_error(OTHER_PROBLEM,
++            "geoip match: insufficient memory available");
++   
++   fread(subnets, db_nsubnets * sizeof(struct geoip_subnet), 1, dbfd);
++   
++   fclose(dbfd);
++   free(index);
++   *count = db_nsubnets;
++   return subnets;
++}
++ 
++static struct geoip_info *
++load_geoip_cc(u_int16_t cc)
++{
++   static struct geoip_info *ginfo;
++   ginfo = malloc(sizeof(struct geoip_info));
++
++   if (!ginfo)
++      return NULL;
++   
++   ginfo->subnets = get_country_subnets(cc, &ginfo->count);
++   ginfo->cc = cc;
++   
++   return ginfo;
++}
++
++static u_int16_t
++check_geoip_cc(char *cc, u_int16_t cc_used[], u_int8_t count)
++{
++   u_int8_t i;
++   u_int16_t cc_int16;
++
++   if (strlen(cc) != 2) /* Country must be 2 chars long according
++                                        to the ISO3166 standard */
++    exit_error(PARAMETER_PROBLEM,
++         "geoip match: invalid country code '%s'", cc);
++
++   // Verification will fail if chars aren't uppercased.
++   // Make sure they are..
++   for (i = 0; i < 2; i++)
++      if (isalnum(cc[i]) != 0)
++         cc[i] = toupper(cc[i]);
++      else
++         exit_error(PARAMETER_PROBLEM,
++               "geoip match:  invalid country code '%s'", cc);
++
++   /* Convert chars into a single 16 bit integer.
++    * FIXME:   This assumes that a country code is
++    *          exactly 2 chars long. If this is
++    *          going to change someday, this whole
++    *          match will need to be rewritten, anyway.
++    *                                  - SJ  */
++   cc_int16 = (cc[0]<<8) + cc[1];
++
++   // Check for presence of value in cc_used
++   for (i = 0; i < count; i++)
++      if (cc_int16 == cc_used[i])
++         return 0; // Present, skip it!
++   
++   return cc_int16;
++}
++
++/* Based on libipt_multiport.c parsing code. */ 
++static u_int8_t
++parse_geoip_cc(const char *ccstr, u_int16_t *cc, struct geoip_info **mem)
++{
++   char *buffer, *cp, *next;
++   u_int8_t i, count = 0;
++   u_int16_t cctmp;
++
++   buffer = strdup(ccstr);
++   if (!buffer) exit_error(OTHER_PROBLEM,
++         "geoip match: insufficient memory available");
++
++   for (cp = buffer, i = 0; cp && i < IPT_GEOIP_MAX; cp = next, i++)
++   {
++      next = strchr(cp, ',');
++      if (next) *next++ = '\0';
++      
++      if ((cctmp = check_geoip_cc(cp, cc, count)) != 0) {
++         if ((mem[count++] = load_geoip_cc(cctmp)) == NULL)
++            exit_error(OTHER_PROBLEM,
++                  "geoip match: insufficient memory available");
++         cc[count-1] = cctmp;
++         }
++   }
++   
++   if (cp) exit_error(PARAMETER_PROBLEM,
++         "geoip match: too many countries specified");
++   free(buffer);
++
++   if (count == 0) exit_error(PARAMETER_PROBLEM,
++         "geoip match: don't know what happened");
++   
++   return count;
++}
++
++static int 
++parse(int c, char **argv, int invert, unsigned int *flags,
++                 const struct ipt_entry *entry,
++                 unsigned int *nfcache,
++                 struct ipt_entry_match **match)
++{
++   struct ipt_geoip_info *info
++      = (struct ipt_geoip_info *)(*match)->data;
++  
++    switch(c) {
++      case '1':
++         // Ensure that IPT_GEOIP_SRC *OR* IPT_GEOIP_DST haven't been used yet.
++         if (*flags & (IPT_GEOIP_SRC | IPT_GEOIP_DST))
++            exit_error(PARAMETER_PROBLEM,
++                  "geoip match: only use --source-country *OR* --destination-country once!");
++ 
++         *flags |= IPT_GEOIP_SRC;
++         *nfcache |= NFC_IP_SRC;
++         break;
++         
++      case '2':
++         // Ensure that IPT_GEOIP_SRC *OR* IPT_GEOIP_DST haven't been used yet.
++         if (*flags & (IPT_GEOIP_SRC | IPT_GEOIP_DST))
++            exit_error(PARAMETER_PROBLEM,
++                  "geoip match: only use --source-country *OR* --destination-country once!");
++ 
++         *flags |= IPT_GEOIP_DST;
++         *nfcache |= NFC_IP_DST;
++         break;
++      
++      default:
++         return 0;
++    }
++    
++    if (invert)
++       *flags |= IPT_GEOIP_INV;
++   
++    info->count = parse_geoip_cc(argv[optind-1], info->cc, info->mem);
++    info->flags = *flags;
++    info->refcount = NULL;
++    //info->fini = &geoip_free;
++
++    return 1;
++}
++
++static void 
++final_check(unsigned int flags)
++{
++   if (!flags)
++      exit_error(PARAMETER_PROBLEM,
++            "geoip match: missing arguments");
++}
++
++static void 
++print(const struct ipt_ip *ip,
++                  const struct ipt_entry_match *match,
++                  int numeric)
++{
++   const struct ipt_geoip_info *info
++      = (const struct ipt_geoip_info *)match->data;
++   
++   u_int8_t i;
++   
++   if (info->flags & IPT_GEOIP_SRC)
++      printf("Source ");
++   else printf("Destination ");
++   
++   if (info->count > 1)
++      printf("countries: ");
++   else printf("country: ");
++   
++   if (info->flags & IPT_GEOIP_INV)
++      printf("! ");
++      
++   for (i = 0; i < info->count; i++)
++       printf("%s%c%c", i ? "," : "", COUNTRY(info->cc[i]));
++   printf(" ");
++}
++
++static void 
++save(const struct ipt_ip *ip,
++                 const struct ipt_entry_match *match)
++{
++   const struct ipt_geoip_info *info
++      = (const struct ipt_geoip_info *)match->data;
++   u_int8_t i;
++
++   if (info->flags & IPT_GEOIP_INV)
++      printf("! ");
++ 
++   if (info->flags & IPT_GEOIP_SRC)
++      printf("--source-country ");
++   else printf("--destination-country ");
++      
++   for (i = 0; i < info->count; i++)
++      printf("%s%c%c", i ? "," : "", COUNTRY(info->cc[i]));
++   printf(" ");
++}
++
++static struct iptables_match geoip = {
++    .name            = "geoip",
++    .version         = IPTABLES_VERSION,
++    .size            = IPT_ALIGN(sizeof(struct ipt_geoip_info)),
++    .userspacesize   = offsetof(struct ipt_geoip_info, mem),
++    .help            = &help,
++    .init            = &init,
++    .parse           = &parse,
++    .final_check     = &final_check,
++    .print           = &print,
++    .save            = &save,
++    .extra_opts      = opts
++};
++
++void _init(void)
++{
++   register_match(&geoip);
++}
+diff -Nur iptables.org/extensions/libipt_geoip.man iptables/extensions/libipt_geoip.man
+--- iptables.org/extensions/libipt_geoip.man	1970-01-01 01:00:00.000000000 +0100
++++ iptables/extensions/libipt_geoip.man	2005-09-15 09:20:28.000000000 +0200
+@@ -0,0 +1,15 @@
++Match a packet by its source or destination country.
++.TP
++[\fB!\fR] \fB--src-cc\fR, \fB--source-country \fIcountry\fR[\fB,\fIcountry\fB,\fIcountry\fB,\fI...\fR]
++Match packet coming from (one of) the specified country(ies)
++.TP
++[\fB!\fR] \fB--dst-cc\fR, \fB--destination-country \fIcountry\fR[\fB,\fIcountry\fB,\fIcountry\fB,\fI...\fR]
++Match packet going to (one of) the specified country(ies)
++.TP
++NOTE:
++The country is inputed by its ISO3166 code.
++.P
++The only extra files you need is a binary db (geoipdb.bin) & its index file (geoipdb.idx).
++Both files are generated from a countries & subnets database with the csv2bin tool,
++available at www.cookinglinux.org/geoip/. Both files MUST also be moved in /var/geoip/
++as the shared library is statically looking for that pathname (ex.: /var/geoip/geoipdb.bin).
================================================================



More information about the pld-cvs-commit mailing list