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
37 #include <linux/netfilter_ipv4/ipt_webmon.h>
40 #define iptables_match xtables_match
44 * XTABLES_VERSION_CODE is only defined in versions 1.4.1 and later, which
45 * also require the use of xtables_register_match
47 * Version 1.4.0 uses register_match like previous versions
49 #ifdef XTABLES_VERSION_CODE
50 #define register_match xtables_register_match
53 unsigned char* read_entire_file(FILE* in
, unsigned long read_block_size
, unsigned long *length
);
55 #define DEFAULT_MAX 300
57 #define SEARCH_LOAD_FILE 100
58 #define DOMAIN_LOAD_FILE 101
59 #define CLEAR_SEARCH 102
60 #define CLEAR_DOMAIN 103
62 static char* domain_load_file
= NULL
;
63 static char* search_load_file
= NULL
;
64 static uint32_t global_max_domains
= DEFAULT_MAX
;
65 static uint32_t global_max_searches
= DEFAULT_MAX
;
67 /* Function which prints out usage message. */
68 static void help(void)
70 printf( "webmon options:\n");
73 static struct option opts
[] =
75 { .name
= "max_domains", .has_arg
= 1, .flag
= 0, .val
= WEBMON_MAXDOMAIN
},
76 { .name
= "max_searches", .has_arg
= 1, .flag
= 0, .val
= WEBMON_MAXSEARCH
},
77 { .name
= "search_load_file", .has_arg
= 1, .flag
= 0, .val
= SEARCH_LOAD_FILE
},
78 { .name
= "domain_load_file", .has_arg
= 1, .flag
= 0, .val
= DOMAIN_LOAD_FILE
},
79 { .name
= "clear_search", .has_arg
= 0, .flag
= 0, .val
= CLEAR_SEARCH
},
80 { .name
= "clear_domain", .has_arg
= 0, .flag
= 0, .val
= CLEAR_DOMAIN
},
85 static void webmon_init(
87 struct xt_entry_match
*match
89 struct ipt_entry_match
*match
, unsigned int *nfcache
93 struct ipt_webmon_info
*info
= (struct ipt_webmon_info
*)match
->data
;
94 info
->max_domains
=DEFAULT_MAX
;
95 info
->max_searches
=DEFAULT_MAX
;
96 info
->ref_count
= NULL
;
100 /* Function which parses command options; returns true if it ate an option */
101 static int parse( int c
,
108 const struct ipt_entry
*entry
,
109 unsigned int *nfcache
,
111 struct ipt_entry_match
**match
114 struct ipt_webmon_info
*info
= (struct ipt_webmon_info
*)(*match
)->data
;
119 case WEBMON_MAXSEARCH
:
120 if( sscanf(argv
[optind
-1], "%ld", &max
) == 0)
122 info
->max_searches
= DEFAULT_MAX
;
127 info
->max_searches
= (uint32_t)max
;
128 global_max_searches
= info
->max_searches
;
131 case WEBMON_MAXDOMAIN
:
132 if( sscanf(argv
[optind
-1], "%ld", &max
) == 0)
134 info
->max_domains
= DEFAULT_MAX
;
139 info
->max_domains
= (uint32_t)max
;
140 global_max_domains
= info
->max_domains
;
143 case SEARCH_LOAD_FILE
:
144 search_load_file
= strdup(optarg
);
146 case DOMAIN_LOAD_FILE
:
147 domain_load_file
= strdup(optarg
);
150 search_load_file
= strdup("/dev/null");
153 domain_load_file
= strdup("/dev/null");
163 static void print_webmon_args( struct ipt_webmon_info
* info
)
165 printf("--max_domains %ld ", (unsigned long int)info
->max_domains
);
166 printf("--max_searches %ld ", (unsigned long int)info
->max_searches
);
170 static void do_load(char* file
, uint32_t max
, unsigned char type
)
174 unsigned char* data
= NULL
;
175 unsigned long data_length
= 0;
176 if(strcmp(file
, "/dev/null") == 0)
178 data
= (unsigned char*)malloc(10);
181 uint32_t* maxp
= (uint32_t*)(data
+1);
182 data_length
= 3+sizeof(uint32_t);
185 data
[ sizeof(uint32_t)+1 ] = ' ';
186 data
[ sizeof(uint32_t)+1 ] = '\0';
191 FILE* in
= fopen(file
, "r");
194 char* file_data
= read_entire_file(in
, 4096, &data_length
);
196 if(file_data
!= NULL
)
198 data_length
= strlen(file_data
) + sizeof(uint32_t)+2;
199 data
= (unsigned char*)malloc(data_length
);
202 uint32_t* maxp
= (uint32_t*)(data
+1);
205 sprintf( (data
+1+sizeof(uint32_t)), "%s", file_data
);
212 if(data
!= NULL
&& data_length
> 0)
215 sockfd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
218 setsockopt(sockfd
, IPPROTO_IP
, WEBMON_SET
, data
, data_length
);
229 static void final_check(unsigned int flags
)
231 do_load(domain_load_file
, global_max_domains
, WEBMON_DOMAIN
);
232 do_load(search_load_file
, global_max_searches
, WEBMON_SEARCH
);
235 /* Prints out the matchinfo. */
237 static void print(const void *ip
, const struct xt_entry_match
*match
, int numeric
)
239 static void print(const struct ipt_ip
*ip
, const struct ipt_entry_match
*match
, int numeric
)
243 struct ipt_webmon_info
*info
= (struct ipt_webmon_info
*)match
->data
;
245 print_webmon_args(info
);
248 /* Saves the union ipt_matchinfo in parsable form to stdout. */
250 static void save(const void *ip
, const struct xt_entry_match
*match
)
252 static void save(const struct ipt_ip
*ip
, const struct ipt_entry_match
*match
)
255 struct ipt_webmon_info
*info
= (struct ipt_webmon_info
*)match
->data
;
256 print_webmon_args(info
);
259 static struct iptables_match webmon
=
263 #ifdef XTABLES_VERSION_CODE
264 .version
= XTABLES_VERSION
,
266 .version
= IPTABLES_VERSION
,
268 .size
= IPT_ALIGN(sizeof(struct ipt_webmon_info
)),
269 .userspacesize
= IPT_ALIGN(sizeof(struct ipt_webmon_info
)),
271 .init
= &webmon_init
,
273 .final_check
= &final_check
,
281 register_match(&webmon
);
285 unsigned char* read_entire_file(FILE* in
, unsigned long read_block_size
, unsigned long *length
)
287 int max_read_size
= read_block_size
;
288 unsigned char* read_string
= (unsigned char*)malloc(max_read_size
+1);
289 unsigned long bytes_read
= 0;
291 while(end_found
== 0)
294 while(nextch
!= EOF
&& bytes_read
< max_read_size
)
299 read_string
[bytes_read
] = (unsigned char)nextch
;
303 read_string
[bytes_read
] = '\0';
304 end_found
= (nextch
== EOF
) ? 1 : 0;
307 unsigned char *new_str
;
308 max_read_size
= max_read_size
+ read_block_size
;
309 new_str
= (unsigned char*)malloc(max_read_size
+1);
310 memcpy(new_str
, read_string
, bytes_read
);
312 read_string
= new_str
;
315 *length
= bytes_read
;