iptables-1.2.9-2.3.1.src.rpm
[iptables.git] / extensions / libip6t_LOG.c
1 /* Shared library add-on to iptables to add LOG support. */
2 #include <stdio.h>
3 #include <netdb.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <syslog.h>
7 #include <getopt.h>
8 #include <ip6tables.h>
9 #include <linux/netfilter_ipv6/ip6_tables.h>
10 #include <linux/netfilter_ipv6/ip6t_LOG.h>
11
12 #define LOG_DEFAULT_LEVEL LOG_WARNING
13
14 /* Function which prints out usage message. */
15 static void
16 help(void)
17 {
18         printf(
19 "LOG v%s options:\n"
20 " --log-level level             Level of logging (numeric or see syslog.conf)\n"
21 " --log-prefix prefix           Prefix log messages with this prefix.\n\n"
22 " --log-tcp-sequence            Log TCP sequence numbers.\n\n"
23 " --log-tcp-options             Log TCP options.\n\n"
24 " --log-ip-options              Log IP options.\n\n",
25 IPTABLES_VERSION);
26 }
27
28 static struct option opts[] = {
29         { .name = "log-level",        .has_arg = 1, .flag = 0, .val = '!' },
30         { .name = "log-prefix",       .has_arg = 1, .flag = 0, .val = '#' },
31         { .name = "log-tcp-sequence", .has_arg = 0, .flag = 0, .val = '1' },
32         { .name = "log-tcp-options",  .has_arg = 0, .flag = 0, .val = '2' },
33         { .name = "log-ip-options",   .has_arg = 0, .flag = 0, .val = '3' },
34         { .name = 0 }
35 };
36
37 /* Initialize the target. */
38 static void
39 init(struct ip6t_entry_target *t, unsigned int *nfcache)
40 {
41         struct ip6t_log_info *loginfo = (struct ip6t_log_info *)t->data;
42
43         loginfo->level = LOG_DEFAULT_LEVEL;
44
45         /* Can't cache this */
46         *nfcache |= NFC_UNKNOWN;
47 }
48
49 struct ip6t_log_names {
50         const char *name;
51         unsigned int level;
52 };
53
54 static struct ip6t_log_names ip6t_log_names[]
55 = { { .name = "alert",   .level = LOG_ALERT },
56     { .name = "crit",    .level = LOG_CRIT },
57     { .name = "debug",   .level = LOG_DEBUG },
58     { .name = "emerg",   .level = LOG_EMERG },
59     { .name = "error",   .level = LOG_ERR },            /* DEPRECATED */
60     { .name = "info",    .level = LOG_INFO },
61     { .name = "notice",  .level = LOG_NOTICE },
62     { .name = "panic",   .level = LOG_EMERG },          /* DEPRECATED */
63     { .name = "warning", .level = LOG_WARNING }
64 };
65
66 static u_int8_t
67 parse_level(const char *level)
68 {
69         unsigned int lev = -1;
70         unsigned int set = 0;
71
72         if (string_to_number(level, 0, 7, &lev) == -1) {
73                 unsigned int i = 0;
74
75                 for (i = 0;
76                      i < sizeof(ip6t_log_names) / sizeof(struct ip6t_log_names);
77                      i++) {
78                         if (strncasecmp(level, ip6t_log_names[i].name,
79                                         strlen(level)) == 0) {
80                                 if (set++)
81                                         exit_error(PARAMETER_PROBLEM,
82                                                    "log-level `%s' ambiguous",
83                                                    level);
84                                 lev = ip6t_log_names[i].level;
85                         }
86                 }
87
88                 if (!set)
89                         exit_error(PARAMETER_PROBLEM,
90                                    "log-level `%s' unknown", level);
91         }
92
93         return (u_int8_t)lev;
94 }
95
96 #define IP6T_LOG_OPT_LEVEL 0x01
97 #define IP6T_LOG_OPT_PREFIX 0x02
98 #define IP6T_LOG_OPT_TCPSEQ 0x04
99 #define IP6T_LOG_OPT_TCPOPT 0x08
100 #define IP6T_LOG_OPT_IPOPT 0x10
101
102 /* Function which parses command options; returns true if it
103    ate an option */
104 static int
105 parse(int c, char **argv, int invert, unsigned int *flags,
106       const struct ip6t_entry *entry,
107       struct ip6t_entry_target **target)
108 {
109         struct ip6t_log_info *loginfo = (struct ip6t_log_info *)(*target)->data;
110
111         switch (c) {
112         case '!':
113                 if (*flags & IP6T_LOG_OPT_LEVEL)
114                         exit_error(PARAMETER_PROBLEM,
115                                    "Can't specify --log-level twice");
116
117                 if (check_inverse(optarg, &invert, NULL, 0))
118                         exit_error(PARAMETER_PROBLEM,
119                                    "Unexpected `!' after --log-level");
120
121                 loginfo->level = parse_level(optarg);
122                 *flags |= IP6T_LOG_OPT_LEVEL;
123                 break;
124
125         case '#':
126                 if (*flags & IP6T_LOG_OPT_PREFIX)
127                         exit_error(PARAMETER_PROBLEM,
128                                    "Can't specify --log-prefix twice");
129
130                 if (check_inverse(optarg, &invert, NULL, 0))
131                         exit_error(PARAMETER_PROBLEM,
132                                    "Unexpected `!' after --log-prefix");
133
134                 if (strlen(optarg) > sizeof(loginfo->prefix) - 1)
135                         exit_error(PARAMETER_PROBLEM,
136                                    "Maximum prefix length %u for --log-prefix",
137                                    sizeof(loginfo->prefix) - 1);
138
139                 strcpy(loginfo->prefix, optarg);
140                 *flags |= IP6T_LOG_OPT_PREFIX;
141                 break;
142
143         case '1':
144                 if (*flags & IP6T_LOG_OPT_TCPSEQ)
145                         exit_error(PARAMETER_PROBLEM,
146                                    "Can't specify --log-tcp-sequence "
147                                    "twice");
148
149                 loginfo->logflags |= IP6T_LOG_TCPSEQ;
150                 *flags |= IP6T_LOG_OPT_TCPSEQ;
151                 break;
152
153         case '2':
154                 if (*flags & IP6T_LOG_OPT_TCPOPT)
155                         exit_error(PARAMETER_PROBLEM,
156                                    "Can't specify --log-tcp-options twice");
157
158                 loginfo->logflags |= IP6T_LOG_TCPOPT;
159                 *flags |= IP6T_LOG_OPT_TCPOPT;
160                 break;
161
162         case '3':
163                 if (*flags & IP6T_LOG_OPT_IPOPT)
164                         exit_error(PARAMETER_PROBLEM,
165                                    "Can't specify --log-ip-options twice");
166
167                 loginfo->logflags |= IP6T_LOG_IPOPT;
168                 *flags |= IP6T_LOG_OPT_IPOPT;
169                 break;
170
171         default:
172                 return 0;
173         }
174
175         return 1;
176 }
177
178 /* Final check; nothing. */
179 static void final_check(unsigned int flags)
180 {
181 }
182
183 /* Prints out the targinfo. */
184 static void
185 print(const struct ip6t_ip6 *ip,
186       const struct ip6t_entry_target *target,
187       int numeric)
188 {
189         const struct ip6t_log_info *loginfo
190                 = (const struct ip6t_log_info *)target->data;
191         unsigned int i = 0;
192
193         printf("LOG ");
194         if (numeric)
195                 printf("flags %u level %u ",
196                        loginfo->logflags, loginfo->level);
197         else {
198                 for (i = 0;
199                      i < sizeof(ip6t_log_names) / sizeof(struct ip6t_log_names);
200                      i++) {
201                         if (loginfo->level == ip6t_log_names[i].level) {
202                                 printf("level %s ", ip6t_log_names[i].name);
203                                 break;
204                         }
205                 }
206                 if (i == sizeof(ip6t_log_names) / sizeof(struct ip6t_log_names))
207                         printf("UNKNOWN level %u ", loginfo->level);
208                 if (loginfo->logflags & IP6T_LOG_TCPSEQ)
209                         printf("tcp-sequence ");
210                 if (loginfo->logflags & IP6T_LOG_TCPOPT)
211                         printf("tcp-options ");
212                 if (loginfo->logflags & IP6T_LOG_IPOPT)
213                         printf("ip-options ");
214                 if (loginfo->logflags & ~(IP6T_LOG_MASK))
215                         printf("unknown-flags ");
216         }
217
218         if (strcmp(loginfo->prefix, "") != 0)
219                 printf("prefix `%s' ", loginfo->prefix);
220 }
221
222 /* Saves the union ip6t_targinfo in parsable form to stdout. */
223 static void
224 save(const struct ip6t_ip6 *ip, const struct ip6t_entry_target *target)
225 {
226         const struct ip6t_log_info *loginfo
227                 = (const struct ip6t_log_info *)target->data;
228
229         if (strcmp(loginfo->prefix, "") != 0)
230                 printf("--log-prefix \"%s\" ", loginfo->prefix);
231
232         if (loginfo->level != LOG_DEFAULT_LEVEL)
233                 printf("--log-level %d ", loginfo->level);
234
235         if (loginfo->logflags & IP6T_LOG_TCPSEQ)
236                 printf("--log-tcp-sequence ");
237         if (loginfo->logflags & IP6T_LOG_TCPOPT)
238                 printf("--log-tcp-options ");
239         if (loginfo->logflags & IP6T_LOG_IPOPT)
240                 printf("--log-ip-options ");
241 }
242
243 static
244 struct ip6tables_target log
245 = {
246     .name          = "LOG",
247     .version       = IPTABLES_VERSION,
248     .size          = IP6T_ALIGN(sizeof(struct ip6t_log_info)),
249     .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_log_info)),
250     .help          = &help,
251     .init          = &init,
252     .parse         = &parse,
253     .final_check   = &final_check,
254     .print         = &print,
255     .save          = &save,
256     .extra_opts    = opts
257 };
258
259 void _init(void)
260 {
261         register_target6(&log);
262 }