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