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>
40 #include <linux/netfilter/xt_webmon.h>
41 #define ipt_webmon_info xt_webmon_info
43 #include <linux/netfilter_ipv4/ipt_webmon.h>
47 #define iptables_match xtables_match
48 #define ip6t_entry_match xt_entry_match
52 * XTABLES_VERSION_CODE is only defined in versions 1.4.1 and later, which
53 * also require the use of xtables_register_match
55 * Version 1.4.0 uses register_match like previous versions
57 #ifdef XTABLES_VERSION_CODE
58 #define register_match6 xtables_register_match
61 unsigned char* read_entire_file(FILE* in
, unsigned long read_block_size
, unsigned long *length
);
63 #define DEFAULT_MAX 300
65 #define SEARCH_LOAD_FILE 100
66 #define DOMAIN_LOAD_FILE 101
67 #define CLEAR_SEARCH 102
68 #define CLEAR_DOMAIN 103
70 static char* domain_load_file
= NULL
;
71 static char* search_load_file
= NULL
;
72 static uint32_t global_max_domains
= DEFAULT_MAX
;
73 static uint32_t global_max_searches
= DEFAULT_MAX
;
75 /* Function which prints out usage message. */
76 static void help(void)
78 printf( "webmon options:\n");
81 static struct option opts
[] =
83 { .name
= "max_domains", .has_arg
= 1, .flag
= 0, .val
= WEBMON_MAXDOMAIN
},
84 { .name
= "max_searches", .has_arg
= 1, .flag
= 0, .val
= WEBMON_MAXSEARCH
},
85 { .name
= "search_load_file", .has_arg
= 1, .flag
= 0, .val
= SEARCH_LOAD_FILE
},
86 { .name
= "domain_load_file", .has_arg
= 1, .flag
= 0, .val
= DOMAIN_LOAD_FILE
},
87 { .name
= "clear_search", .has_arg
= 0, .flag
= 0, .val
= CLEAR_SEARCH
},
88 { .name
= "clear_domain", .has_arg
= 0, .flag
= 0, .val
= CLEAR_DOMAIN
},
93 static void webmon_init(
95 struct xt_entry_match
*match
97 struct ip6t_entry_match
*match
, unsigned int *nfcache
101 struct ipt_webmon_info
*info
= (struct ipt_webmon_info
*)match
->data
;
102 info
->max_domains
=DEFAULT_MAX
;
103 info
->max_searches
=DEFAULT_MAX
;
104 info
->ref_count
= NULL
;
108 /* Function which parses command options; returns true if it ate an option */
109 static int parse( int c
,
116 const struct ip6t_entry
*entry
,
117 unsigned int *nfcache
,
119 struct ip6t_entry_match
**match
122 struct ipt_webmon_info
*info
= (struct ipt_webmon_info
*)(*match
)->data
;
127 case WEBMON_MAXSEARCH
:
128 if( sscanf(argv
[optind
-1], "%ld", &max
) == 0)
130 info
->max_searches
= DEFAULT_MAX
;
135 info
->max_searches
= (uint32_t)max
;
136 global_max_searches
= info
->max_searches
;
139 case WEBMON_MAXDOMAIN
:
140 if( sscanf(argv
[optind
-1], "%ld", &max
) == 0)
142 info
->max_domains
= DEFAULT_MAX
;
147 info
->max_domains
= (uint32_t)max
;
148 global_max_domains
= info
->max_domains
;
151 case SEARCH_LOAD_FILE
:
152 search_load_file
= strdup(optarg
);
154 case DOMAIN_LOAD_FILE
:
155 domain_load_file
= strdup(optarg
);
158 search_load_file
= strdup("/dev/null");
161 domain_load_file
= strdup("/dev/null");
172 static void print_webmon_args( struct ipt_webmon_info
* info
)
174 printf("--max_domains %ld ", (unsigned long int)info
->max_domains
);
175 printf("--max_searches %ld ", (unsigned long int)info
->max_searches
);
179 static void do_load(char* file
, uint32_t max
, unsigned char type
)
183 unsigned char* data
= NULL
;
184 unsigned long data_length
= 0;
185 if(strcmp(file
, "/dev/null") == 0)
187 data
= (unsigned char*)malloc(10);
190 uint32_t* maxp
= (uint32_t*)(data
+1);
191 data_length
= 3+sizeof(uint32_t);
194 data
[ sizeof(uint32_t)+1 ] = ' ';
195 data
[ sizeof(uint32_t)+1 ] = '\0';
200 FILE* in
= fopen(file
, "r");
203 char* file_data
= read_entire_file(in
, 4096, &data_length
);
205 if(file_data
!= NULL
)
207 data_length
= strlen(file_data
) + sizeof(uint32_t)+2;
208 data
= (unsigned char*)malloc(data_length
);
211 uint32_t* maxp
= (uint32_t*)(data
+1);
214 sprintf( (data
+1+sizeof(uint32_t)), "%s", file_data
);
221 if(data
!= NULL
&& data_length
> 0)
224 sockfd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
227 setsockopt(sockfd
, IPPROTO_IP
, WEBMON_SET
, data
, data_length
);
238 static void final_check(unsigned int flags
)
240 do_load(domain_load_file
, global_max_domains
, WEBMON_DOMAIN
);
241 do_load(search_load_file
, global_max_searches
, WEBMON_SEARCH
);
244 /* Prints out the matchinfo. */
246 static void print(const void *ip
, const struct xt_entry_match
*match
, int numeric
)
248 static void print(const struct ip6t_ip6
*ip
, const struct ip6t_entry_match
*match
, int numeric
)
252 struct ipt_webmon_info
*info
= (struct ipt_webmon_info
*)match
->data
;
254 print_webmon_args(info
);
257 /* Saves the union ipt_matchinfo in parsable form to stdout. */
259 static void save(const void *ip
, const struct xt_entry_match
*match
)
261 static void save(const struct ip6t_ip6
*ip
, const struct ip6t_entry_match
*match
)
264 struct ipt_webmon_info
*info
= (struct ipt_webmon_info
*)match
->data
;
265 print_webmon_args(info
);
268 static struct ip6tables_match webmon
=
272 #ifdef XTABLES_VERSION_CODE
273 .version
= XTABLES_VERSION
,
276 .version
= IPTABLES_VERSION
,
278 .size
= IP6T_ALIGN(sizeof(struct ipt_webmon_info
)),
279 .userspacesize
= IP6T_ALIGN(sizeof(struct ipt_webmon_info
)),
281 .init
= &webmon_init
,
283 .final_check
= &final_check
,
291 register_match6(&webmon
);
295 unsigned char* read_entire_file(FILE* in
, unsigned long read_block_size
, unsigned long *length
)
297 int max_read_size
= read_block_size
;
298 unsigned char* read_string
= (unsigned char*)malloc(max_read_size
+1);
299 unsigned long bytes_read
= 0;
301 while(end_found
== 0)
304 while(nextch
!= EOF
&& bytes_read
< max_read_size
)
309 read_string
[bytes_read
] = (unsigned char)nextch
;
313 read_string
[bytes_read
] = '\0';
314 end_found
= (nextch
== EOF
) ? 1 : 0;
317 unsigned char *new_str
;
318 max_read_size
= max_read_size
+ read_block_size
;
319 new_str
= (unsigned char*)malloc(max_read_size
+1);
320 memcpy(new_str
, read_string
, bytes_read
);
322 read_string
= new_str
;
325 *length
= bytes_read
;