1 /* webmon -- An iptables extension to match URLs in HTTP requests
2 * This module can match using string match or regular expressions
3 * Originally designed for use with Gargoyle router firmware (gargoyle-router.com)
6 * Copyright © 2008-2010 by Eric Bishop <eric@gargoyle-router.com>
8 * This file is free software: you may copy, redistribute and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 2 of the License, or (at your
11 * option) any later version.
13 * This file is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #include <arpa/inet.h>
32 * in iptables 1.4.0 and higher, iptables.h includes xtables.h, which
33 * we can use to check whether we need to deal with the new requirements
34 * in pre-processor directives below
36 #include <ip6tables.h>
37 #include <linux/netfilter_ipv6/ip6_tables.h>
39 #include <linux/netfilter_ipv4/ipt_webmon.h>
42 #define iptables_match xtables_match
43 #define ip6t_entry_match xt_entry_match
47 * XTABLES_VERSION_CODE is only defined in versions 1.4.1 and later, which
48 * also require the use of xtables_register_match
50 * Version 1.4.0 uses register_match like previous versions
52 #ifdef XTABLES_VERSION_CODE
53 #define register_match6 xtables_register_match
56 unsigned char* read_entire_file(FILE* in
, unsigned long read_block_size
, unsigned long *length
);
58 #define DEFAULT_MAX 300
60 #define SEARCH_LOAD_FILE 100
61 #define DOMAIN_LOAD_FILE 101
62 #define CLEAR_SEARCH 102
63 #define CLEAR_DOMAIN 103
65 static char* domain_load_file
= NULL
;
66 static char* search_load_file
= NULL
;
67 static uint32_t global_max_domains
= DEFAULT_MAX
;
68 static uint32_t global_max_searches
= DEFAULT_MAX
;
70 /* Function which prints out usage message. */
71 static void help(void)
73 printf( "webmon options:\n");
76 static struct option opts
[] =
78 { .name
= "max_domains", .has_arg
= 1, .flag
= 0, .val
= WEBMON_MAXDOMAIN
},
79 { .name
= "max_searches", .has_arg
= 1, .flag
= 0, .val
= WEBMON_MAXSEARCH
},
80 { .name
= "search_load_file", .has_arg
= 1, .flag
= 0, .val
= SEARCH_LOAD_FILE
},
81 { .name
= "domain_load_file", .has_arg
= 1, .flag
= 0, .val
= DOMAIN_LOAD_FILE
},
82 { .name
= "clear_search", .has_arg
= 0, .flag
= 0, .val
= CLEAR_SEARCH
},
83 { .name
= "clear_domain", .has_arg
= 0, .flag
= 0, .val
= CLEAR_DOMAIN
},
88 static void webmon_init(
90 struct xt_entry_match
*match
92 struct ip6t_entry_match
*match
, unsigned int *nfcache
96 struct ipt_webmon_info
*info
= (struct ipt_webmon_info
*)match
->data
;
97 info
->max_domains
=DEFAULT_MAX
;
98 info
->max_searches
=DEFAULT_MAX
;
99 info
->ref_count
= NULL
;
103 /* Function which parses command options; returns true if it ate an option */
104 static int parse( int c
,
111 const struct ip6t_entry
*entry
,
112 unsigned int *nfcache
,
114 struct ip6t_entry_match
**match
117 struct ipt_webmon_info
*info
= (struct ipt_webmon_info
*)(*match
)->data
;
122 case WEBMON_MAXSEARCH
:
123 if( sscanf(argv
[optind
-1], "%ld", &max
) == 0)
125 info
->max_searches
= DEFAULT_MAX
;
130 info
->max_searches
= (uint32_t)max
;
131 global_max_searches
= info
->max_searches
;
134 case WEBMON_MAXDOMAIN
:
135 if( sscanf(argv
[optind
-1], "%ld", &max
) == 0)
137 info
->max_domains
= DEFAULT_MAX
;
142 info
->max_domains
= (uint32_t)max
;
143 global_max_domains
= info
->max_domains
;
146 case SEARCH_LOAD_FILE
:
147 search_load_file
= strdup(optarg
);
149 case DOMAIN_LOAD_FILE
:
150 domain_load_file
= strdup(optarg
);
153 search_load_file
= strdup("/dev/null");
156 domain_load_file
= strdup("/dev/null");
167 static void print_webmon_args( struct ipt_webmon_info
* info
)
169 printf("--max_domains %ld ", (unsigned long int)info
->max_domains
);
170 printf("--max_searches %ld ", (unsigned long int)info
->max_searches
);
174 static void do_load(char* file
, uint32_t max
, unsigned char type
)
178 unsigned char* data
= NULL
;
179 unsigned long data_length
= 0;
180 if(strcmp(file
, "/dev/null") == 0)
182 data
= (unsigned char*)malloc(10);
185 uint32_t* maxp
= (uint32_t*)(data
+1);
186 data_length
= 3+sizeof(uint32_t);
189 data
[ sizeof(uint32_t)+1 ] = ' ';
190 data
[ sizeof(uint32_t)+1 ] = '\0';
195 FILE* in
= fopen(file
, "r");
198 char* file_data
= read_entire_file(in
, 4096, &data_length
);
200 if(file_data
!= NULL
)
202 data_length
= strlen(file_data
) + sizeof(uint32_t)+2;
203 data
= (unsigned char*)malloc(data_length
);
206 uint32_t* maxp
= (uint32_t*)(data
+1);
209 sprintf( (data
+1+sizeof(uint32_t)), "%s", file_data
);
216 if(data
!= NULL
&& data_length
> 0)
219 sockfd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
222 setsockopt(sockfd
, IPPROTO_IP
, WEBMON_SET
, data
, data_length
);
233 static void final_check(unsigned int flags
)
235 do_load(domain_load_file
, global_max_domains
, WEBMON_DOMAIN
);
236 do_load(search_load_file
, global_max_searches
, WEBMON_SEARCH
);
239 /* Prints out the matchinfo. */
241 static void print(const void *ip
, const struct xt_entry_match
*match
, int numeric
)
243 static void print(const struct ip6t_ip6
*ip
, const struct ip6t_entry_match
*match
, int numeric
)
247 struct ipt_webmon_info
*info
= (struct ipt_webmon_info
*)match
->data
;
249 print_webmon_args(info
);
252 /* Saves the union ipt_matchinfo in parsable form to stdout. */
254 static void save(const void *ip
, const struct xt_entry_match
*match
)
256 static void save(const struct ip6t_ip6
*ip
, const struct ip6t_entry_match
*match
)
259 struct ipt_webmon_info
*info
= (struct ipt_webmon_info
*)match
->data
;
260 print_webmon_args(info
);
263 static struct ip6tables_match webmon
=
267 #ifdef XTABLES_VERSION_CODE
268 .version
= XTABLES_VERSION
,
271 .version
= IPTABLES_VERSION
,
273 .size
= IP6T_ALIGN(sizeof(struct ipt_webmon_info
)),
274 .userspacesize
= IP6T_ALIGN(sizeof(struct ipt_webmon_info
)),
276 .init
= &webmon_init
,
278 .final_check
= &final_check
,
286 register_match6(&webmon
);
290 unsigned char* read_entire_file(FILE* in
, unsigned long read_block_size
, unsigned long *length
)
292 int max_read_size
= read_block_size
;
293 unsigned char* read_string
= (unsigned char*)malloc(max_read_size
+1);
294 unsigned long bytes_read
= 0;
296 while(end_found
== 0)
299 while(nextch
!= EOF
&& bytes_read
< max_read_size
)
304 read_string
[bytes_read
] = (unsigned char)nextch
;
308 read_string
[bytes_read
] = '\0';
309 end_found
= (nextch
== EOF
) ? 1 : 0;
312 unsigned char *new_str
;
313 max_read_size
= max_read_size
+ read_block_size
;
314 new_str
= (unsigned char*)malloc(max_read_size
+1);
315 memcpy(new_str
, read_string
, bytes_read
);
317 read_string
= new_str
;
320 *length
= bytes_read
;