libipt_LOG.c revision 182f3f62acbcb88b615b3d7d5940e316472be049
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. */ 21static void 22help(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", 32IPTABLES_VERSION); 33} 34 35static 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. */ 46static void 47init(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 55struct ipt_log_names { 56 const char *name; 57 unsigned int level; 58}; 59 60static 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 72static u_int8_t 73parse_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 */ 111static int 112parse(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. */ 199static void final_check(unsigned int flags) 200{ 201} 202 203/* Prints out the targinfo. */ 204static void 205print(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. */ 245static void 246save(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 267static 268struct 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 283void _init(void) 284{ 285 register_target(&log); 286} 287