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