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