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. */ 21 static void 22 help(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", 32 IPTABLES_VERSION); 33 } 34 35 static 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. */ 46 static void 47 init(struct ip6t_entry_target *t, unsigned int *nfcache) 48 { 49 struct ip6t_log_info *loginfo = (struct ip6t_log_info *)t->data; 50 51 loginfo->level = LOG_DEFAULT_LEVEL; 52 53 } 54 55 struct ip6t_log_names { 56 const char *name; 57 unsigned int level; 58 }; 59 60 static struct ip6t_log_names ip6t_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 72 static u_int8_t 73 parse_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(ip6t_log_names) / sizeof(struct ip6t_log_names); 83 i++) { 84 if (strncasecmp(level, ip6t_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 = ip6t_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 IP6T_LOG_OPT_LEVEL 0x01 103 #define IP6T_LOG_OPT_PREFIX 0x02 104 #define IP6T_LOG_OPT_TCPSEQ 0x04 105 #define IP6T_LOG_OPT_TCPOPT 0x08 106 #define IP6T_LOG_OPT_IPOPT 0x10 107 #define IP6T_LOG_OPT_UID 0x20 108 109 /* Function which parses command options; returns true if it 110 ate an option */ 111 static int 112 parse(int c, char **argv, int invert, unsigned int *flags, 113 const struct ip6t_entry *entry, 114 struct ip6t_entry_target **target) 115 { 116 struct ip6t_log_info *loginfo = (struct ip6t_log_info *)(*target)->data; 117 118 switch (c) { 119 case '!': 120 if (*flags & IP6T_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 |= IP6T_LOG_OPT_LEVEL; 130 break; 131 132 case '#': 133 if (*flags & IP6T_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) == 0) 147 exit_error(PARAMETER_PROBLEM, 148 "No prefix specified for --log-prefix"); 149 150 if (strlen(optarg) != strlen(strtok(optarg, "\n"))) 151 exit_error(PARAMETER_PROBLEM, 152 "Newlines not allowed in --log-prefix"); 153 154 strcpy(loginfo->prefix, optarg); 155 *flags |= IP6T_LOG_OPT_PREFIX; 156 break; 157 158 case '1': 159 if (*flags & IP6T_LOG_OPT_TCPSEQ) 160 exit_error(PARAMETER_PROBLEM, 161 "Can't specify --log-tcp-sequence " 162 "twice"); 163 164 loginfo->logflags |= IP6T_LOG_TCPSEQ; 165 *flags |= IP6T_LOG_OPT_TCPSEQ; 166 break; 167 168 case '2': 169 if (*flags & IP6T_LOG_OPT_TCPOPT) 170 exit_error(PARAMETER_PROBLEM, 171 "Can't specify --log-tcp-options twice"); 172 173 loginfo->logflags |= IP6T_LOG_TCPOPT; 174 *flags |= IP6T_LOG_OPT_TCPOPT; 175 break; 176 177 case '3': 178 if (*flags & IP6T_LOG_OPT_IPOPT) 179 exit_error(PARAMETER_PROBLEM, 180 "Can't specify --log-ip-options twice"); 181 182 loginfo->logflags |= IP6T_LOG_IPOPT; 183 *flags |= IP6T_LOG_OPT_IPOPT; 184 break; 185 186 case '4': 187 if (*flags & IP6T_LOG_OPT_UID) 188 exit_error(PARAMETER_PROBLEM, 189 "Can't specify --log-uid twice"); 190 191 loginfo->logflags |= IP6T_LOG_UID; 192 *flags |= IP6T_LOG_OPT_UID; 193 break; 194 195 default: 196 return 0; 197 } 198 199 return 1; 200 } 201 202 /* Final check; nothing. */ 203 static void final_check(unsigned int flags) 204 { 205 } 206 207 /* Prints out the targinfo. */ 208 static void 209 print(const struct ip6t_ip6 *ip, 210 const struct ip6t_entry_target *target, 211 int numeric) 212 { 213 const struct ip6t_log_info *loginfo 214 = (const struct ip6t_log_info *)target->data; 215 unsigned int i = 0; 216 217 printf("LOG "); 218 if (numeric) 219 printf("flags %u level %u ", 220 loginfo->logflags, loginfo->level); 221 else { 222 for (i = 0; 223 i < sizeof(ip6t_log_names) / sizeof(struct ip6t_log_names); 224 i++) { 225 if (loginfo->level == ip6t_log_names[i].level) { 226 printf("level %s ", ip6t_log_names[i].name); 227 break; 228 } 229 } 230 if (i == sizeof(ip6t_log_names) / sizeof(struct ip6t_log_names)) 231 printf("UNKNOWN level %u ", loginfo->level); 232 if (loginfo->logflags & IP6T_LOG_TCPSEQ) 233 printf("tcp-sequence "); 234 if (loginfo->logflags & IP6T_LOG_TCPOPT) 235 printf("tcp-options "); 236 if (loginfo->logflags & IP6T_LOG_IPOPT) 237 printf("ip-options "); 238 if (loginfo->logflags & IP6T_LOG_UID) 239 printf("uid "); 240 if (loginfo->logflags & ~(IP6T_LOG_MASK)) 241 printf("unknown-flags "); 242 } 243 244 if (strcmp(loginfo->prefix, "") != 0) 245 printf("prefix `%s' ", loginfo->prefix); 246 } 247 248 /* Saves the union ip6t_targinfo in parsable form to stdout. */ 249 static void 250 save(const struct ip6t_ip6 *ip, const struct ip6t_entry_target *target) 251 { 252 const struct ip6t_log_info *loginfo 253 = (const struct ip6t_log_info *)target->data; 254 255 if (strcmp(loginfo->prefix, "") != 0) 256 printf("--log-prefix \"%s\" ", loginfo->prefix); 257 258 if (loginfo->level != LOG_DEFAULT_LEVEL) 259 printf("--log-level %d ", loginfo->level); 260 261 if (loginfo->logflags & IP6T_LOG_TCPSEQ) 262 printf("--log-tcp-sequence "); 263 if (loginfo->logflags & IP6T_LOG_TCPOPT) 264 printf("--log-tcp-options "); 265 if (loginfo->logflags & IP6T_LOG_IPOPT) 266 printf("--log-ip-options "); 267 if (loginfo->logflags & IP6T_LOG_UID) 268 printf("--log-uid "); 269 } 270 271 static 272 struct ip6tables_target log 273 = { 274 .name = "LOG", 275 .version = IPTABLES_VERSION, 276 .size = IP6T_ALIGN(sizeof(struct ip6t_log_info)), 277 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_log_info)), 278 .help = &help, 279 .init = &init, 280 .parse = &parse, 281 .final_check = &final_check, 282 .print = &print, 283 .save = &save, 284 .extra_opts = opts 285 }; 286 287 void _init(void) 288 { 289 register_target6(&log); 290 } 291