1 /* (C) 1999-2001 Paul `Rusty' Russell 2 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/spinlock.h> 14 #include <linux/skbuff.h> 15 #include <linux/if_arp.h> 16 #include <linux/ip.h> 17 #include <net/ipv6.h> 18 #include <net/icmp.h> 19 #include <net/udp.h> 20 #include <net/tcp.h> 21 #include <net/route.h> 22 23 #include <linux/netfilter.h> 24 #include <linux/netfilter/xt_LOG.h> 25 #include <net/netfilter/nf_log.h> 26 27 static struct nf_loginfo default_loginfo = { 28 .type = NF_LOG_TYPE_LOG, 29 .u = { 30 .log = { 31 .level = LOGLEVEL_NOTICE, 32 .logflags = NF_LOG_MASK, 33 }, 34 }, 35 }; 36 37 /* One level of recursion won't kill us */ 38 static void dump_ipv4_packet(struct nf_log_buf *m, 39 const struct nf_loginfo *info, 40 const struct sk_buff *skb, unsigned int iphoff) 41 { 42 struct iphdr _iph; 43 const struct iphdr *ih; 44 unsigned int logflags; 45 46 if (info->type == NF_LOG_TYPE_LOG) 47 logflags = info->u.log.logflags; 48 else 49 logflags = NF_LOG_MASK; 50 51 ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); 52 if (ih == NULL) { 53 nf_log_buf_add(m, "TRUNCATED"); 54 return; 55 } 56 57 /* Important fields: 58 * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ 59 /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ 60 nf_log_buf_add(m, "SRC=%pI4 DST=%pI4 ", &ih->saddr, &ih->daddr); 61 62 /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ 63 nf_log_buf_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", 64 ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, 65 ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); 66 67 /* Max length: 6 "CE DF MF " */ 68 if (ntohs(ih->frag_off) & IP_CE) 69 nf_log_buf_add(m, "CE "); 70 if (ntohs(ih->frag_off) & IP_DF) 71 nf_log_buf_add(m, "DF "); 72 if (ntohs(ih->frag_off) & IP_MF) 73 nf_log_buf_add(m, "MF "); 74 75 /* Max length: 11 "FRAG:65535 " */ 76 if (ntohs(ih->frag_off) & IP_OFFSET) 77 nf_log_buf_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); 78 79 if ((logflags & XT_LOG_IPOPT) && 80 ih->ihl * 4 > sizeof(struct iphdr)) { 81 const unsigned char *op; 82 unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; 83 unsigned int i, optsize; 84 85 optsize = ih->ihl * 4 - sizeof(struct iphdr); 86 op = skb_header_pointer(skb, iphoff+sizeof(_iph), 87 optsize, _opt); 88 if (op == NULL) { 89 nf_log_buf_add(m, "TRUNCATED"); 90 return; 91 } 92 93 /* Max length: 127 "OPT (" 15*4*2chars ") " */ 94 nf_log_buf_add(m, "OPT ("); 95 for (i = 0; i < optsize; i++) 96 nf_log_buf_add(m, "%02X", op[i]); 97 nf_log_buf_add(m, ") "); 98 } 99 100 switch (ih->protocol) { 101 case IPPROTO_TCP: 102 if (nf_log_dump_tcp_header(m, skb, ih->protocol, 103 ntohs(ih->frag_off) & IP_OFFSET, 104 iphoff+ih->ihl*4, logflags)) 105 return; 106 break; 107 case IPPROTO_UDP: 108 case IPPROTO_UDPLITE: 109 if (nf_log_dump_udp_header(m, skb, ih->protocol, 110 ntohs(ih->frag_off) & IP_OFFSET, 111 iphoff+ih->ihl*4)) 112 return; 113 break; 114 case IPPROTO_ICMP: { 115 struct icmphdr _icmph; 116 const struct icmphdr *ich; 117 static const size_t required_len[NR_ICMP_TYPES+1] 118 = { [ICMP_ECHOREPLY] = 4, 119 [ICMP_DEST_UNREACH] 120 = 8 + sizeof(struct iphdr), 121 [ICMP_SOURCE_QUENCH] 122 = 8 + sizeof(struct iphdr), 123 [ICMP_REDIRECT] 124 = 8 + sizeof(struct iphdr), 125 [ICMP_ECHO] = 4, 126 [ICMP_TIME_EXCEEDED] 127 = 8 + sizeof(struct iphdr), 128 [ICMP_PARAMETERPROB] 129 = 8 + sizeof(struct iphdr), 130 [ICMP_TIMESTAMP] = 20, 131 [ICMP_TIMESTAMPREPLY] = 20, 132 [ICMP_ADDRESS] = 12, 133 [ICMP_ADDRESSREPLY] = 12 }; 134 135 /* Max length: 11 "PROTO=ICMP " */ 136 nf_log_buf_add(m, "PROTO=ICMP "); 137 138 if (ntohs(ih->frag_off) & IP_OFFSET) 139 break; 140 141 /* Max length: 25 "INCOMPLETE [65535 bytes] " */ 142 ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, 143 sizeof(_icmph), &_icmph); 144 if (ich == NULL) { 145 nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", 146 skb->len - iphoff - ih->ihl*4); 147 break; 148 } 149 150 /* Max length: 18 "TYPE=255 CODE=255 " */ 151 nf_log_buf_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); 152 153 /* Max length: 25 "INCOMPLETE [65535 bytes] " */ 154 if (ich->type <= NR_ICMP_TYPES && 155 required_len[ich->type] && 156 skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { 157 nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", 158 skb->len - iphoff - ih->ihl*4); 159 break; 160 } 161 162 switch (ich->type) { 163 case ICMP_ECHOREPLY: 164 case ICMP_ECHO: 165 /* Max length: 19 "ID=65535 SEQ=65535 " */ 166 nf_log_buf_add(m, "ID=%u SEQ=%u ", 167 ntohs(ich->un.echo.id), 168 ntohs(ich->un.echo.sequence)); 169 break; 170 171 case ICMP_PARAMETERPROB: 172 /* Max length: 14 "PARAMETER=255 " */ 173 nf_log_buf_add(m, "PARAMETER=%u ", 174 ntohl(ich->un.gateway) >> 24); 175 break; 176 case ICMP_REDIRECT: 177 /* Max length: 24 "GATEWAY=255.255.255.255 " */ 178 nf_log_buf_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); 179 /* Fall through */ 180 case ICMP_DEST_UNREACH: 181 case ICMP_SOURCE_QUENCH: 182 case ICMP_TIME_EXCEEDED: 183 /* Max length: 3+maxlen */ 184 if (!iphoff) { /* Only recurse once. */ 185 nf_log_buf_add(m, "["); 186 dump_ipv4_packet(m, info, skb, 187 iphoff + ih->ihl*4+sizeof(_icmph)); 188 nf_log_buf_add(m, "] "); 189 } 190 191 /* Max length: 10 "MTU=65535 " */ 192 if (ich->type == ICMP_DEST_UNREACH && 193 ich->code == ICMP_FRAG_NEEDED) { 194 nf_log_buf_add(m, "MTU=%u ", 195 ntohs(ich->un.frag.mtu)); 196 } 197 } 198 break; 199 } 200 /* Max Length */ 201 case IPPROTO_AH: { 202 struct ip_auth_hdr _ahdr; 203 const struct ip_auth_hdr *ah; 204 205 if (ntohs(ih->frag_off) & IP_OFFSET) 206 break; 207 208 /* Max length: 9 "PROTO=AH " */ 209 nf_log_buf_add(m, "PROTO=AH "); 210 211 /* Max length: 25 "INCOMPLETE [65535 bytes] " */ 212 ah = skb_header_pointer(skb, iphoff+ih->ihl*4, 213 sizeof(_ahdr), &_ahdr); 214 if (ah == NULL) { 215 nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", 216 skb->len - iphoff - ih->ihl*4); 217 break; 218 } 219 220 /* Length: 15 "SPI=0xF1234567 " */ 221 nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi)); 222 break; 223 } 224 case IPPROTO_ESP: { 225 struct ip_esp_hdr _esph; 226 const struct ip_esp_hdr *eh; 227 228 /* Max length: 10 "PROTO=ESP " */ 229 nf_log_buf_add(m, "PROTO=ESP "); 230 231 if (ntohs(ih->frag_off) & IP_OFFSET) 232 break; 233 234 /* Max length: 25 "INCOMPLETE [65535 bytes] " */ 235 eh = skb_header_pointer(skb, iphoff+ih->ihl*4, 236 sizeof(_esph), &_esph); 237 if (eh == NULL) { 238 nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", 239 skb->len - iphoff - ih->ihl*4); 240 break; 241 } 242 243 /* Length: 15 "SPI=0xF1234567 " */ 244 nf_log_buf_add(m, "SPI=0x%x ", ntohl(eh->spi)); 245 break; 246 } 247 /* Max length: 10 "PROTO 255 " */ 248 default: 249 nf_log_buf_add(m, "PROTO=%u ", ih->protocol); 250 } 251 252 /* Max length: 15 "UID=4294967295 " */ 253 if ((logflags & XT_LOG_UID) && !iphoff) 254 nf_log_dump_sk_uid_gid(m, skb->sk); 255 256 /* Max length: 16 "MARK=0xFFFFFFFF " */ 257 if (!iphoff && skb->mark) 258 nf_log_buf_add(m, "MARK=0x%x ", skb->mark); 259 260 /* Proto Max log string length */ 261 /* IP: 40+46+6+11+127 = 230 */ 262 /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ 263 /* UDP: 10+max(25,20) = 35 */ 264 /* UDPLITE: 14+max(25,20) = 39 */ 265 /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ 266 /* ESP: 10+max(25)+15 = 50 */ 267 /* AH: 9+max(25)+15 = 49 */ 268 /* unknown: 10 */ 269 270 /* (ICMP allows recursion one level deep) */ 271 /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ 272 /* maxlen = 230+ 91 + 230 + 252 = 803 */ 273 } 274 275 static void dump_ipv4_mac_header(struct nf_log_buf *m, 276 const struct nf_loginfo *info, 277 const struct sk_buff *skb) 278 { 279 struct net_device *dev = skb->dev; 280 unsigned int logflags = 0; 281 282 if (info->type == NF_LOG_TYPE_LOG) 283 logflags = info->u.log.logflags; 284 285 if (!(logflags & XT_LOG_MACDECODE)) 286 goto fallback; 287 288 switch (dev->type) { 289 case ARPHRD_ETHER: 290 nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", 291 eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, 292 ntohs(eth_hdr(skb)->h_proto)); 293 return; 294 default: 295 break; 296 } 297 298 fallback: 299 nf_log_buf_add(m, "MAC="); 300 if (dev->hard_header_len && 301 skb->mac_header != skb->network_header) { 302 const unsigned char *p = skb_mac_header(skb); 303 unsigned int i; 304 305 nf_log_buf_add(m, "%02x", *p++); 306 for (i = 1; i < dev->hard_header_len; i++, p++) 307 nf_log_buf_add(m, ":%02x", *p); 308 } 309 nf_log_buf_add(m, " "); 310 } 311 312 static void nf_log_ip_packet(struct net *net, u_int8_t pf, 313 unsigned int hooknum, const struct sk_buff *skb, 314 const struct net_device *in, 315 const struct net_device *out, 316 const struct nf_loginfo *loginfo, 317 const char *prefix) 318 { 319 struct nf_log_buf *m; 320 321 /* FIXME: Disabled from containers until syslog ns is supported */ 322 if (!net_eq(net, &init_net)) 323 return; 324 325 m = nf_log_buf_open(); 326 327 if (!loginfo) 328 loginfo = &default_loginfo; 329 330 nf_log_dump_packet_common(m, pf, hooknum, skb, in, 331 out, loginfo, prefix); 332 333 if (in != NULL) 334 dump_ipv4_mac_header(m, loginfo, skb); 335 336 dump_ipv4_packet(m, loginfo, skb, 0); 337 338 nf_log_buf_close(m); 339 } 340 341 static struct nf_logger nf_ip_logger __read_mostly = { 342 .name = "nf_log_ipv4", 343 .type = NF_LOG_TYPE_LOG, 344 .logfn = nf_log_ip_packet, 345 .me = THIS_MODULE, 346 }; 347 348 static int __net_init nf_log_ipv4_net_init(struct net *net) 349 { 350 nf_log_set(net, NFPROTO_IPV4, &nf_ip_logger); 351 return 0; 352 } 353 354 static void __net_exit nf_log_ipv4_net_exit(struct net *net) 355 { 356 nf_log_unset(net, &nf_ip_logger); 357 } 358 359 static struct pernet_operations nf_log_ipv4_net_ops = { 360 .init = nf_log_ipv4_net_init, 361 .exit = nf_log_ipv4_net_exit, 362 }; 363 364 static int __init nf_log_ipv4_init(void) 365 { 366 int ret; 367 368 ret = register_pernet_subsys(&nf_log_ipv4_net_ops); 369 if (ret < 0) 370 return ret; 371 372 ret = nf_log_register(NFPROTO_IPV4, &nf_ip_logger); 373 if (ret < 0) { 374 pr_err("failed to register logger\n"); 375 goto err1; 376 } 377 378 return 0; 379 380 err1: 381 unregister_pernet_subsys(&nf_log_ipv4_net_ops); 382 return ret; 383 } 384 385 static void __exit nf_log_ipv4_exit(void) 386 { 387 unregister_pernet_subsys(&nf_log_ipv4_net_ops); 388 nf_log_unregister(&nf_ip_logger); 389 } 390 391 module_init(nf_log_ipv4_init); 392 module_exit(nf_log_ipv4_exit); 393 394 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 395 MODULE_DESCRIPTION("Netfilter IPv4 packet logging"); 396 MODULE_LICENSE("GPL"); 397 MODULE_ALIAS_NF_LOGGER(AF_INET, 0); 398
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.