libipt_LOG.c revision 32b8e61e4e5bd405d9ad07bf9468498dfbb19f9e
1/* Shared library add-on to iptables to add LOG support. */ 2#include <stdbool.h> 3#include <stdio.h> 4#include <netdb.h> 5#include <string.h> 6#include <stdlib.h> 7#include <syslog.h> 8#include <getopt.h> 9#include <xtables.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 20static void LOG_help(void) 21{ 22 printf( 23"LOG target options:\n" 24" --log-level level Level of logging (numeric or see syslog.conf)\n" 25" --log-prefix prefix Prefix log messages with this prefix.\n\n" 26" --log-tcp-sequence Log TCP sequence numbers.\n\n" 27" --log-tcp-options Log TCP options.\n\n" 28" --log-ip-options Log IP options.\n\n" 29" --log-uid Log UID owning the local socket.\n\n" 30" --log-macdecode Decode MAC addresses and protocol.\n\n"); 31} 32 33static const struct option LOG_opts[] = { 34 {.name = "log-level", .has_arg = true, .val = '!'}, 35 {.name = "log-prefix", .has_arg = true, .val = '#'}, 36 {.name = "log-tcp-sequence", .has_arg = false, .val = '1'}, 37 {.name = "log-tcp-options", .has_arg = false, .val = '2'}, 38 {.name = "log-ip-options", .has_arg = false, .val = '3'}, 39 {.name = "log-uid", .has_arg = false, .val = '4'}, 40 {.name = "log-macdecode", .has_arg = false, .val = '5'}, 41 XT_GETOPT_TABLEEND, 42}; 43 44static void LOG_init(struct xt_entry_target *t) 45{ 46 struct ipt_log_info *loginfo = (struct ipt_log_info *)t->data; 47 48 loginfo->level = LOG_DEFAULT_LEVEL; 49 50} 51 52struct ipt_log_names { 53 const char *name; 54 unsigned int level; 55}; 56 57static const struct ipt_log_names ipt_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 (!xtables_strtoui(level, NULL, &lev, 0, 7)) { 76 unsigned int i = 0; 77 78 for (i = 0; i < ARRAY_SIZE(ipt_log_names); ++i) 79 if (strncasecmp(level, ipt_log_names[i].name, 80 strlen(level)) == 0) { 81 if (set++) 82 xtables_error(PARAMETER_PROBLEM, 83 "log-level `%s' ambiguous", 84 level); 85 lev = ipt_log_names[i].level; 86 } 87 88 if (!set) 89 xtables_error(PARAMETER_PROBLEM, 90 "log-level `%s' unknown", level); 91 } 92 93 return lev; 94} 95 96#define IPT_LOG_OPT_LEVEL 0x01 97#define IPT_LOG_OPT_PREFIX 0x02 98#define IPT_LOG_OPT_TCPSEQ 0x04 99#define IPT_LOG_OPT_TCPOPT 0x08 100#define IPT_LOG_OPT_IPOPT 0x10 101#define IPT_LOG_OPT_UID 0x20 102#define IPT_LOG_OPT_MACDECODE 0x40 103 104static int LOG_parse(int c, char **argv, int invert, unsigned int *flags, 105 const void *entry, struct xt_entry_target **target) 106{ 107 struct ipt_log_info *loginfo = (struct ipt_log_info *)(*target)->data; 108 109 switch (c) { 110 case '!': 111 if (*flags & IPT_LOG_OPT_LEVEL) 112 xtables_error(PARAMETER_PROBLEM, 113 "Can't specify --log-level twice"); 114 115 if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) 116 xtables_error(PARAMETER_PROBLEM, 117 "Unexpected `!' after --log-level"); 118 119 loginfo->level = parse_level(optarg); 120 *flags |= IPT_LOG_OPT_LEVEL; 121 break; 122 123 case '#': 124 if (*flags & IPT_LOG_OPT_PREFIX) 125 xtables_error(PARAMETER_PROBLEM, 126 "Can't specify --log-prefix twice"); 127 128 if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) 129 xtables_error(PARAMETER_PROBLEM, 130 "Unexpected `!' after --log-prefix"); 131 132 if (strlen(optarg) > sizeof(loginfo->prefix) - 1) 133 xtables_error(PARAMETER_PROBLEM, 134 "Maximum prefix length %u for --log-prefix", 135 (unsigned int)sizeof(loginfo->prefix) - 1); 136 137 if (strlen(optarg) == 0) 138 xtables_error(PARAMETER_PROBLEM, 139 "No prefix specified for --log-prefix"); 140 141 if (strlen(optarg) != strlen(strtok(optarg, "\n"))) 142 xtables_error(PARAMETER_PROBLEM, 143 "Newlines not allowed in --log-prefix"); 144 145 strcpy(loginfo->prefix, optarg); 146 *flags |= IPT_LOG_OPT_PREFIX; 147 break; 148 149 case '1': 150 if (*flags & IPT_LOG_OPT_TCPSEQ) 151 xtables_error(PARAMETER_PROBLEM, 152 "Can't specify --log-tcp-sequence " 153 "twice"); 154 155 loginfo->logflags |= IPT_LOG_TCPSEQ; 156 *flags |= IPT_LOG_OPT_TCPSEQ; 157 break; 158 159 case '2': 160 if (*flags & IPT_LOG_OPT_TCPOPT) 161 xtables_error(PARAMETER_PROBLEM, 162 "Can't specify --log-tcp-options twice"); 163 164 loginfo->logflags |= IPT_LOG_TCPOPT; 165 *flags |= IPT_LOG_OPT_TCPOPT; 166 break; 167 168 case '3': 169 if (*flags & IPT_LOG_OPT_IPOPT) 170 xtables_error(PARAMETER_PROBLEM, 171 "Can't specify --log-ip-options twice"); 172 173 loginfo->logflags |= IPT_LOG_IPOPT; 174 *flags |= IPT_LOG_OPT_IPOPT; 175 break; 176 177 case '4': 178 if (*flags & IPT_LOG_OPT_UID) 179 xtables_error(PARAMETER_PROBLEM, 180 "Can't specify --log-uid twice"); 181 182 loginfo->logflags |= IPT_LOG_UID; 183 *flags |= IPT_LOG_OPT_UID; 184 break; 185 186 case '5': 187 if (*flags & IPT_LOG_OPT_MACDECODE) 188 xtables_error(PARAMETER_PROBLEM, 189 "Can't specifiy --log-macdecode twice"); 190 191 loginfo->logflags |= IPT_LOG_MACDECODE; 192 *flags |= IPT_LOG_OPT_MACDECODE; 193 break; 194 default: 195 return 0; 196 } 197 198 return 1; 199} 200 201static void LOG_print(const void *ip, const struct xt_entry_target *target, 202 int numeric) 203{ 204 const struct ipt_log_info *loginfo 205 = (const struct ipt_log_info *)target->data; 206 unsigned int i = 0; 207 208 printf("LOG "); 209 if (numeric) 210 printf("flags %u level %u ", 211 loginfo->logflags, loginfo->level); 212 else { 213 for (i = 0; i < ARRAY_SIZE(ipt_log_names); ++i) 214 if (loginfo->level == ipt_log_names[i].level) { 215 printf("level %s ", ipt_log_names[i].name); 216 break; 217 } 218 if (i == ARRAY_SIZE(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_MACDECODE) 229 printf("macdecode "); 230 if (loginfo->logflags & ~(IPT_LOG_MASK)) 231 printf("unknown-flags "); 232 } 233 234 if (strcmp(loginfo->prefix, "") != 0) 235 printf("prefix `%s' ", loginfo->prefix); 236} 237 238static void LOG_save(const void *ip, const struct xt_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 "); 245 xtables_save_string(loginfo->prefix); 246 } 247 248 if (loginfo->level != LOG_DEFAULT_LEVEL) 249 printf("--log-level %d ", loginfo->level); 250 251 if (loginfo->logflags & IPT_LOG_TCPSEQ) 252 printf("--log-tcp-sequence "); 253 if (loginfo->logflags & IPT_LOG_TCPOPT) 254 printf("--log-tcp-options "); 255 if (loginfo->logflags & IPT_LOG_IPOPT) 256 printf("--log-ip-options "); 257 if (loginfo->logflags & IPT_LOG_UID) 258 printf("--log-uid "); 259 if (loginfo->logflags & IPT_LOG_MACDECODE) 260 printf("--log-macdecode "); 261} 262 263static struct xtables_target log_tg_reg = { 264 .name = "LOG", 265 .version = XTABLES_VERSION, 266 .family = NFPROTO_IPV4, 267 .size = XT_ALIGN(sizeof(struct ipt_log_info)), 268 .userspacesize = XT_ALIGN(sizeof(struct ipt_log_info)), 269 .help = LOG_help, 270 .init = LOG_init, 271 .parse = LOG_parse, 272 .print = LOG_print, 273 .save = LOG_save, 274 .extra_opts = LOG_opts, 275}; 276 277void _init(void) 278{ 279 xtables_register_target(&log_tg_reg); 280} 281