iptables-1.3.2-20050720
[iptables.git] / extensions / libipt_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 <iptables.h>
9 #include <linux/netfilter_ipv4/ip_tables.h>
10 #include <linux/netfilter_ipv4/ipt_LOG.h>
11
12 #define LOG_DEFAULT_LEVEL LOG_WARNING
13
14 #ifndef IPT_LOG_UID /* Old kernel */
15 #define IPT_LOG_UID     0x08    /* Log UID owning local socket */
16 #undef  IPT_LOG_MASK
17 #define IPT_LOG_MASK    0x0f
18 #endif
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 ipt_entry_target *t, unsigned int *nfcache)
48 {
49         struct ipt_log_info *loginfo = (struct ipt_log_info *)t->data;
50
51         loginfo->level = LOG_DEFAULT_LEVEL;
52
53 }
54
55 struct ipt_log_names {
56         const char *name;
57         unsigned int level;
58 };
59
60 static struct ipt_log_names ipt_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(ipt_log_names) / sizeof(struct ipt_log_names);
83                      i++) {
84                         if (strncasecmp(level, ipt_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 = ipt_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 IPT_LOG_OPT_LEVEL 0x01
103 #define IPT_LOG_OPT_PREFIX 0x02
104 #define IPT_LOG_OPT_TCPSEQ 0x04
105 #define IPT_LOG_OPT_TCPOPT 0x08
106 #define IPT_LOG_OPT_IPOPT 0x10
107 #define IPT_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 ipt_entry *entry,
114       struct ipt_entry_target **target)
115 {
116         struct ipt_log_info *loginfo = (struct ipt_log_info *)(*target)->data;
117
118         switch (c) {
119         case '!':
120                 if (*flags & IPT_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 |= IPT_LOG_OPT_LEVEL;
130                 break;
131
132         case '#':
133                 if (*flags & IPT_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) != strlen(strtok(optarg, "\n")))
147                         exit_error(PARAMETER_PROBLEM,
148                                    "Newlines not allowed in --log-prefix");
149
150                 strcpy(loginfo->prefix, optarg);
151                 *flags |= IPT_LOG_OPT_PREFIX;
152                 break;
153
154         case '1':
155                 if (*flags & IPT_LOG_OPT_TCPSEQ)
156                         exit_error(PARAMETER_PROBLEM,
157                                    "Can't specify --log-tcp-sequence "
158                                    "twice");
159
160                 loginfo->logflags |= IPT_LOG_TCPSEQ;
161                 *flags |= IPT_LOG_OPT_TCPSEQ;
162                 break;
163
164         case '2':
165                 if (*flags & IPT_LOG_OPT_TCPOPT)
166                         exit_error(PARAMETER_PROBLEM,
167                                    "Can't specify --log-tcp-options twice");
168
169                 loginfo->logflags |= IPT_LOG_TCPOPT;
170                 *flags |= IPT_LOG_OPT_TCPOPT;
171                 break;
172
173         case '3':
174                 if (*flags & IPT_LOG_OPT_IPOPT)
175                         exit_error(PARAMETER_PROBLEM,
176                                    "Can't specify --log-ip-options twice");
177
178                 loginfo->logflags |= IPT_LOG_IPOPT;
179                 *flags |= IPT_LOG_OPT_IPOPT;
180                 break;
181
182         case '4':
183                 if (*flags & IPT_LOG_OPT_UID)
184                         exit_error(PARAMETER_PROBLEM,
185                                    "Can't specify --log-uid twice");
186
187                 loginfo->logflags |= IPT_LOG_UID;
188                 *flags |= IPT_LOG_OPT_UID;
189                 break;
190
191         default:
192                 return 0;
193         }
194
195         return 1;
196 }
197
198 /* Final check; nothing. */
199 static void final_check(unsigned int flags)
200 {
201 }
202
203 /* Prints out the targinfo. */
204 static void
205 print(const struct ipt_ip *ip,
206       const struct ipt_entry_target *target,
207       int numeric)
208 {
209         const struct ipt_log_info *loginfo
210                 = (const struct ipt_log_info *)target->data;
211         unsigned int i = 0;
212
213         printf("LOG ");
214         if (numeric)
215                 printf("flags %u level %u ",
216                        loginfo->logflags, loginfo->level);
217         else {
218                 for (i = 0;
219                      i < sizeof(ipt_log_names) / sizeof(struct ipt_log_names);
220                      i++) {
221                         if (loginfo->level == ipt_log_names[i].level) {
222                                 printf("level %s ", ipt_log_names[i].name);
223                                 break;
224                         }
225                 }
226                 if (i == sizeof(ipt_log_names) / sizeof(struct ipt_log_names))
227                         printf("UNKNOWN level %u ", loginfo->level);
228                 if (loginfo->logflags & IPT_LOG_TCPSEQ)
229                         printf("tcp-sequence ");
230                 if (loginfo->logflags & IPT_LOG_TCPOPT)
231                         printf("tcp-options ");
232                 if (loginfo->logflags & IPT_LOG_IPOPT)
233                         printf("ip-options ");
234                 if (loginfo->logflags & IPT_LOG_UID)
235                         printf("uid ");
236                 if (loginfo->logflags & ~(IPT_LOG_MASK))
237                         printf("unknown-flags ");
238         }
239
240         if (strcmp(loginfo->prefix, "") != 0)
241                 printf("prefix `%s' ", loginfo->prefix);
242 }
243
244 /* Saves the union ipt_targinfo in parsable form to stdout. */
245 static void
246 save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
247 {
248         const struct ipt_log_info *loginfo
249                 = (const struct ipt_log_info *)target->data;
250
251         if (strcmp(loginfo->prefix, "") != 0)
252                 printf("--log-prefix \"%s\" ", loginfo->prefix);
253
254         if (loginfo->level != LOG_DEFAULT_LEVEL)
255                 printf("--log-level %d ", loginfo->level);
256
257         if (loginfo->logflags & IPT_LOG_TCPSEQ)
258                 printf("--log-tcp-sequence ");
259         if (loginfo->logflags & IPT_LOG_TCPOPT)
260                 printf("--log-tcp-options ");
261         if (loginfo->logflags & IPT_LOG_IPOPT)
262                 printf("--log-ip-options ");
263         if (loginfo->logflags & IPT_LOG_UID)
264                 printf("--log-uid ");
265 }
266
267 static
268 struct iptables_target log
269 = {
270     .name          = "LOG",
271     .version       = IPTABLES_VERSION,
272     .size          = IPT_ALIGN(sizeof(struct ipt_log_info)),
273     .userspacesize = IPT_ALIGN(sizeof(struct ipt_log_info)),
274     .help          = &help,
275     .init          = &init,
276     .parse         = &parse,
277     .final_check   = &final_check,
278     .print         = &print,
279     .save          = &save,
280     .extra_opts    = opts
281 };
282
283 void _init(void)
284 {
285         register_target(&log);
286 }