libipt_LOG.c revision f46e1afd45c6d735c8bb8f5a67286780ff40be6a
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/* Function which prints out usage message. */ 15static void 16help(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" --log-uid Log UID owning the local socket.\n\n", 26IPTABLES_VERSION); 27} 28 29static struct option opts[] = { 30 { .name = "log-level", .has_arg = 1, .flag = 0, .val = '!' }, 31 { .name = "log-prefix", .has_arg = 1, .flag = 0, .val = '#' }, 32 { .name = "log-tcp-sequence", .has_arg = 0, .flag = 0, .val = '1' }, 33 { .name = "log-tcp-options", .has_arg = 0, .flag = 0, .val = '2' }, 34 { .name = "log-ip-options", .has_arg = 0, .flag = 0, .val = '3' }, 35 { .name = "log-uid", .has_arg = 0, .flag = 0, .val = '4' }, 36 { .name = 0 } 37}; 38 39/* Initialize the target. */ 40static void 41init(struct ipt_entry_target *t, unsigned int *nfcache) 42{ 43 struct ipt_log_info *loginfo = (struct ipt_log_info *)t->data; 44 45 loginfo->level = LOG_DEFAULT_LEVEL; 46 47 /* Can't cache this */ 48 *nfcache |= NFC_UNKNOWN; 49} 50 51struct ipt_log_names { 52 const char *name; 53 unsigned int level; 54}; 55 56static struct ipt_log_names ipt_log_names[] 57= { { .name = "alert", .level = LOG_ALERT }, 58 { .name = "crit", .level = LOG_CRIT }, 59 { .name = "debug", .level = LOG_DEBUG }, 60 { .name = "emerg", .level = LOG_EMERG }, 61 { .name = "error", .level = LOG_ERR }, /* DEPRECATED */ 62 { .name = "info", .level = LOG_INFO }, 63 { .name = "notice", .level = LOG_NOTICE }, 64 { .name = "panic", .level = LOG_EMERG }, /* DEPRECATED */ 65 { .name = "warning", .level = LOG_WARNING } 66}; 67 68static u_int8_t 69parse_level(const char *level) 70{ 71 unsigned int lev = -1; 72 unsigned int set = 0; 73 74 if (string_to_number(level, 0, 7, &lev) == -1) { 75 unsigned int i = 0; 76 77 for (i = 0; 78 i < sizeof(ipt_log_names) / sizeof(struct ipt_log_names); 79 i++) { 80 if (strncasecmp(level, ipt_log_names[i].name, 81 strlen(level)) == 0) { 82 if (set++) 83 exit_error(PARAMETER_PROBLEM, 84 "log-level `%s' ambiguous", 85 level); 86 lev = ipt_log_names[i].level; 87 } 88 } 89 90 if (!set) 91 exit_error(PARAMETER_PROBLEM, 92 "log-level `%s' unknown", level); 93 } 94 95 return (u_int8_t)lev; 96} 97 98#define IPT_LOG_OPT_LEVEL 0x01 99#define IPT_LOG_OPT_PREFIX 0x02 100#define IPT_LOG_OPT_TCPSEQ 0x04 101#define IPT_LOG_OPT_TCPOPT 0x08 102#define IPT_LOG_OPT_IPOPT 0x10 103#define IPT_LOG_OPT_UID 0x20 104 105/* Function which parses command options; returns true if it 106 ate an option */ 107static int 108parse(int c, char **argv, int invert, unsigned int *flags, 109 const struct ipt_entry *entry, 110 struct ipt_entry_target **target) 111{ 112 struct ipt_log_info *loginfo = (struct ipt_log_info *)(*target)->data; 113 114 switch (c) { 115 case '!': 116 if (*flags & IPT_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 |= IPT_LOG_OPT_LEVEL; 126 break; 127 128 case '#': 129 if (*flags & IPT_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 strcpy(loginfo->prefix, optarg); 143 *flags |= IPT_LOG_OPT_PREFIX; 144 break; 145 146 case '1': 147 if (*flags & IPT_LOG_OPT_TCPSEQ) 148 exit_error(PARAMETER_PROBLEM, 149 "Can't specify --log-tcp-sequence " 150 "twice"); 151 152 loginfo->logflags |= IPT_LOG_TCPSEQ; 153 *flags |= IPT_LOG_OPT_TCPSEQ; 154 break; 155 156 case '2': 157 if (*flags & IPT_LOG_OPT_TCPOPT) 158 exit_error(PARAMETER_PROBLEM, 159 "Can't specify --log-tcp-options twice"); 160 161 loginfo->logflags |= IPT_LOG_TCPOPT; 162 *flags |= IPT_LOG_OPT_TCPOPT; 163 break; 164 165 case '3': 166 if (*flags & IPT_LOG_OPT_IPOPT) 167 exit_error(PARAMETER_PROBLEM, 168 "Can't specify --log-ip-options twice"); 169 170 loginfo->logflags |= IPT_LOG_IPOPT; 171 *flags |= IPT_LOG_OPT_IPOPT; 172 break; 173 174 case '4': 175 if (*flags & IPT_LOG_OPT_UID) 176 exit_error(PARAMETER_PROBLEM, 177 "Can't specify --log-uid twice"); 178 179 loginfo->logflags |= IPT_LOG_UID; 180 *flags |= IPT_LOG_OPT_UID; 181 break; 182 183 default: 184 return 0; 185 } 186 187 return 1; 188} 189 190/* Final check; nothing. */ 191static void final_check(unsigned int flags) 192{ 193} 194 195/* Prints out the targinfo. */ 196static void 197print(const struct ipt_ip *ip, 198 const struct ipt_entry_target *target, 199 int numeric) 200{ 201 const struct ipt_log_info *loginfo 202 = (const struct ipt_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(ipt_log_names) / sizeof(struct ipt_log_names); 212 i++) { 213 if (loginfo->level == ipt_log_names[i].level) { 214 printf("level %s ", ipt_log_names[i].name); 215 break; 216 } 217 } 218 if (i == sizeof(ipt_log_names) / sizeof(struct ipt_log_names)) 219 printf("UNKNOWN level %u ", loginfo->level); 220 if (loginfo->logflags & IPT_LOG_TCPSEQ) 221 printf("tcp-sequence "); 222 if (loginfo->logflags & IPT_LOG_TCPOPT) 223 printf("tcp-options "); 224 if (loginfo->logflags & IPT_LOG_IPOPT) 225 printf("ip-options "); 226 if (loginfo->logflags & IPT_LOG_UID) 227 printf("uid "); 228 if (loginfo->logflags & ~(IPT_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 ipt_targinfo in parsable form to stdout. */ 237static void 238save(const struct ipt_ip *ip, const struct ipt_entry_target *target) 239{ 240 const struct ipt_log_info *loginfo 241 = (const struct ipt_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 & IPT_LOG_TCPSEQ) 250 printf("--log-tcp-sequence "); 251 if (loginfo->logflags & IPT_LOG_TCPOPT) 252 printf("--log-tcp-options "); 253 if (loginfo->logflags & IPT_LOG_IPOPT) 254 printf("--log-ip-options "); 255 if (loginfo->logflags & IPT_LOG_UID) 256 printf("--log-uid "); 257} 258 259static 260struct iptables_target log 261= { 262 .name = "LOG", 263 .version = IPTABLES_VERSION, 264 .size = IPT_ALIGN(sizeof(struct ipt_log_info)), 265 .userspacesize = IPT_ALIGN(sizeof(struct ipt_log_info)), 266 .help = &help, 267 .init = &init, 268 .parse = &parse, 269 .final_check = &final_check, 270 .print = &print, 271 .save = &save, 272 .extra_opts = opts 273}; 274 275void _init(void) 276{ 277 register_target(&log); 278} 279