1/* 2 * (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org> 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ 9 10#include "internal/internal.h" 11 12static int __snprintf_l3protocol(char *buf, 13 unsigned int len, 14 const struct nf_conntrack *ct) 15{ 16 return (snprintf(buf, len, "%-8s %u ", 17 l3proto2str[ct->head.orig.l3protonum] == NULL ? 18 "unknown" : l3proto2str[ct->head.orig.l3protonum], 19 ct->head.orig.l3protonum)); 20} 21 22int __snprintf_protocol(char *buf, 23 unsigned int len, 24 const struct nf_conntrack *ct) 25{ 26 return (snprintf(buf, len, "%-8s %u ", 27 proto2str[ct->head.orig.protonum] == NULL ? 28 "unknown" : proto2str[ct->head.orig.protonum], 29 ct->head.orig.protonum)); 30} 31 32static int __snprintf_timeout(char *buf, 33 unsigned int len, 34 const struct nf_conntrack *ct) 35{ 36 return snprintf(buf, len, "%u ", ct->timeout); 37} 38 39static int __snprintf_protoinfo(char *buf, 40 unsigned int len, 41 const struct nf_conntrack *ct) 42{ 43 return snprintf(buf, len, "%s ", 44 ct->protoinfo.tcp.state < TCP_CONNTRACK_MAX ? 45 states[ct->protoinfo.tcp.state] : 46 states[TCP_CONNTRACK_NONE]); 47} 48 49static int __snprintf_protoinfo_sctp(char *buf, 50 unsigned int len, 51 const struct nf_conntrack *ct) 52{ 53 return snprintf(buf, len, "%s ", 54 ct->protoinfo.sctp.state < SCTP_CONNTRACK_MAX ? 55 sctp_states[ct->protoinfo.sctp.state] : 56 sctp_states[SCTP_CONNTRACK_NONE]); 57} 58 59static int __snprintf_protoinfo_dccp(char *buf, 60 unsigned int len, 61 const struct nf_conntrack *ct) 62{ 63 return snprintf(buf, len, "%s ", 64 ct->protoinfo.dccp.state < DCCP_CONNTRACK_MAX ? 65 sctp_states[ct->protoinfo.dccp.state] : 66 sctp_states[DCCP_CONNTRACK_NONE]); 67} 68 69static int __snprintf_address_ipv4(char *buf, 70 unsigned int len, 71 const struct __nfct_tuple *tuple, 72 const char *src_tag, 73 const char *dst_tag) 74{ 75 int ret, size = 0, offset = 0; 76 struct in_addr src = { .s_addr = tuple->src.v4 }; 77 struct in_addr dst = { .s_addr = tuple->dst.v4 }; 78 79 ret = snprintf(buf, len, "%s=%s ", src_tag, inet_ntoa(src)); 80 BUFFER_SIZE(ret, size, len, offset); 81 82 ret = snprintf(buf+offset, len, "%s=%s ", dst_tag, inet_ntoa(dst)); 83 BUFFER_SIZE(ret, size, len, offset); 84 85 return size; 86} 87 88static int __snprintf_address_ipv6(char *buf, 89 unsigned int len, 90 const struct __nfct_tuple *tuple, 91 const char *src_tag, 92 const char *dst_tag) 93{ 94 int ret, size = 0, offset = 0; 95 struct in6_addr src; 96 struct in6_addr dst; 97 char tmp[INET6_ADDRSTRLEN]; 98 99 memcpy(&src, &tuple->src.v6, sizeof(struct in6_addr)); 100 memcpy(&dst, &tuple->dst.v6, sizeof(struct in6_addr)); 101 102 if (!inet_ntop(AF_INET6, &src, tmp, sizeof(tmp))) 103 return -1; 104 105 ret = snprintf(buf, len, "%s=%s ", src_tag, tmp); 106 BUFFER_SIZE(ret, size, len, offset); 107 108 if (!inet_ntop(AF_INET6, &dst, tmp, sizeof(tmp))) 109 return -1; 110 111 ret = snprintf(buf+offset, len-size, "%s=%s ", dst_tag, tmp); 112 BUFFER_SIZE(ret, size, len, offset); 113 114 return size; 115} 116 117int __snprintf_address(char *buf, 118 unsigned int len, 119 const struct __nfct_tuple *tuple, 120 const char *src_tag, 121 const char *dst_tag) 122{ 123 int size = 0; 124 125 switch (tuple->l3protonum) { 126 case AF_INET: 127 size = __snprintf_address_ipv4(buf, len, tuple, 128 src_tag, dst_tag); 129 break; 130 case AF_INET6: 131 size = __snprintf_address_ipv6(buf, len, tuple, 132 src_tag, dst_tag); 133 break; 134 } 135 136 return size; 137} 138 139int __snprintf_proto(char *buf, 140 unsigned int len, 141 const struct __nfct_tuple *tuple) 142{ 143 int size = 0; 144 145 switch(tuple->protonum) { 146 case IPPROTO_TCP: 147 case IPPROTO_UDP: 148 case IPPROTO_UDPLITE: 149 case IPPROTO_SCTP: 150 case IPPROTO_DCCP: 151 return snprintf(buf, len, "sport=%u dport=%u ", 152 ntohs(tuple->l4src.tcp.port), 153 ntohs(tuple->l4dst.tcp.port)); 154 break; 155 case IPPROTO_GRE: 156 return snprintf(buf, len, "srckey=0x%x dstkey=0x%x ", 157 ntohs(tuple->l4src.all), 158 ntohs(tuple->l4dst.all)); 159 break; 160 case IPPROTO_ICMP: 161 case IPPROTO_ICMPV6: 162 /* The ID only makes sense some ICMP messages but we want to 163 * display the same output that /proc/net/ip_conntrack does */ 164 return (snprintf(buf, len, "type=%d code=%d id=%d ", 165 tuple->l4dst.icmp.type, 166 tuple->l4dst.icmp.code, 167 ntohs(tuple->l4src.icmp.id))); 168 break; 169 } 170 171 return size; 172} 173 174static int 175__snprintf_tuple_zone(char *buf, unsigned int len, const char *pfx, 176 const struct __nfct_tuple *tuple) 177{ 178 return (snprintf(buf, len, "zone-%s=%u ", pfx, tuple->zone)); 179} 180 181static int __snprintf_status_assured(char *buf, 182 unsigned int len, 183 const struct nf_conntrack *ct) 184{ 185 int size = 0; 186 187 if (ct->status & IPS_ASSURED) 188 size = snprintf(buf, len, "[ASSURED] "); 189 190 return size; 191} 192 193static int __snprintf_status_not_seen_reply(char *buf, 194 unsigned int len, 195 const struct nf_conntrack *ct) 196{ 197 int size = 0; 198 199 if (!(ct->status & IPS_SEEN_REPLY)) 200 size = snprintf(buf, len, "[UNREPLIED] "); 201 202 return size; 203} 204 205static int __snprintf_counters(char *buf, 206 unsigned int len, 207 const struct nf_conntrack *ct, 208 int dir) 209{ 210 return (snprintf(buf, len, "packets=%llu bytes=%llu ", 211 (unsigned long long) ct->counters[dir].packets, 212 (unsigned long long) ct->counters[dir].bytes)); 213} 214 215static int 216__snprintf_mark(char *buf, unsigned int len, const struct nf_conntrack *ct) 217{ 218 return (snprintf(buf, len, "mark=%u ", ct->mark)); 219} 220 221static int 222__snprintf_secmark(char *buf, unsigned int len, const struct nf_conntrack *ct) 223{ 224 return (snprintf(buf, len, "secmark=%u ", ct->secmark)); 225} 226 227static int 228__snprintf_use(char *buf, unsigned int len, const struct nf_conntrack *ct) 229{ 230 return (snprintf(buf, len, "use=%u ", ct->use)); 231} 232 233static int 234__snprintf_id(char *buf, unsigned int len, const struct nf_conntrack *ct) 235{ 236 return (snprintf(buf, len, "id=%u ", ct->id)); 237} 238 239static int 240__snprintf_zone(char *buf, unsigned int len, const struct nf_conntrack *ct) 241{ 242 return (snprintf(buf, len, "zone=%u ", ct->zone)); 243} 244 245static int 246__snprintf_secctx(char *buf, unsigned int len, const struct nf_conntrack *ct) 247{ 248 return (snprintf(buf, len, "secctx=%s ", ct->secctx)); 249} 250 251static int 252__snprintf_timestamp_start(char *buf, unsigned int len, 253 const struct nf_conntrack *ct) 254{ 255 time_t start = (time_t)(ct->timestamp.start / NSEC_PER_SEC); 256 char *tmp = ctime(&start); 257 258 /* overwrite \n in the ctime() output. */ 259 tmp[strlen(tmp)-1] = '\0'; 260 return (snprintf(buf, len, "[start=%s] ", tmp)); 261} 262 263static int 264__snprintf_timestamp_stop(char *buf, unsigned int len, 265 const struct nf_conntrack *ct) 266{ 267 time_t stop = (time_t)(ct->timestamp.stop / NSEC_PER_SEC); 268 char *tmp = ctime(&stop); 269 270 /* overwrite \n in the ctime() output. */ 271 tmp[strlen(tmp)-1] = '\0'; 272 return (snprintf(buf, len, "[stop=%s] ", tmp)); 273} 274 275static int 276__snprintf_timestamp_delta(char *buf, unsigned int len, 277 const struct nf_conntrack *ct) 278{ 279 time_t delta_time, stop; 280 281 if (ct->timestamp.stop == 0) 282 time(&stop); 283 else 284 stop = (time_t)(ct->timestamp.stop / NSEC_PER_SEC); 285 286 delta_time = stop - (time_t)(ct->timestamp.start / NSEC_PER_SEC); 287 288 return (snprintf(buf, len, "delta-time=%llu ", 289 (unsigned long long)delta_time)); 290} 291 292static int 293__snprintf_helper_name(char *buf, unsigned int len, const struct nf_conntrack *ct) 294{ 295 return (snprintf(buf, len, "helper=%s ", ct->helper_name)); 296} 297 298int 299__snprintf_connlabels(char *buf, unsigned int len, 300 struct nfct_labelmap *map, 301 const struct nfct_bitmask *b, const char *fmt) 302{ 303 unsigned int i, max; 304 int ret, size = 0, offset = 0; 305 306 max = nfct_bitmask_maxbit(b); 307 for (i = 0; i <= max && len; i++) { 308 const char *name; 309 if (!nfct_bitmask_test_bit(b, i)) 310 continue; 311 name = nfct_labelmap_get_name(map, i); 312 if (!name || strcmp(name, "") == 0) 313 continue; 314 315 ret = snprintf(buf + offset, len, fmt, name); 316 BUFFER_SIZE(ret, size, len, offset); 317 } 318 return size; 319} 320 321static int 322__snprintf_clabels(char *buf, unsigned int len, 323 const struct nf_conntrack *ct, struct nfct_labelmap *map) 324{ 325 const struct nfct_bitmask *b = nfct_get_attr(ct, ATTR_CONNLABELS); 326 int ret, size = 0, offset = 0; 327 328 if (!b) 329 return 0; 330 331 ret = snprintf(buf, len, "labels="); 332 BUFFER_SIZE(ret, size, len, offset); 333 334 ret = __snprintf_connlabels(buf + offset, len, map, b, "%s,"); 335 336 BUFFER_SIZE(ret, size, len, offset); 337 338 offset--; /* remove last , */ 339 size--; 340 ret = snprintf(buf + offset, len, " "); 341 BUFFER_SIZE(ret, size, len, offset); 342 343 return size; 344} 345 346int __snprintf_conntrack_default(char *buf, 347 unsigned int len, 348 const struct nf_conntrack *ct, 349 unsigned int msg_type, 350 unsigned int flags, 351 struct nfct_labelmap *map) 352{ 353 int ret = 0, size = 0, offset = 0; 354 355 switch(msg_type) { 356 case NFCT_T_NEW: 357 ret = snprintf(buf, len, "%9s ", "[NEW]"); 358 break; 359 case NFCT_T_UPDATE: 360 ret = snprintf(buf, len, "%9s ", "[UPDATE]"); 361 break; 362 case NFCT_T_DESTROY: 363 ret = snprintf(buf, len, "%9s ", "[DESTROY]"); 364 break; 365 default: 366 break; 367 } 368 369 BUFFER_SIZE(ret, size, len, offset); 370 371 if (flags & NFCT_OF_SHOW_LAYER3) { 372 ret = __snprintf_l3protocol(buf+offset, len, ct); 373 BUFFER_SIZE(ret, size, len, offset); 374 } 375 376 ret = __snprintf_protocol(buf+offset, len, ct); 377 BUFFER_SIZE(ret, size, len, offset); 378 379 if (test_bit(ATTR_TIMEOUT, ct->head.set)) { 380 ret = __snprintf_timeout(buf+offset, len, ct); 381 BUFFER_SIZE(ret, size, len, offset); 382 } 383 384 if (test_bit(ATTR_TCP_STATE, ct->head.set)) { 385 ret = __snprintf_protoinfo(buf+offset, len, ct); 386 BUFFER_SIZE(ret, size, len, offset); 387 } 388 389 if (test_bit(ATTR_SCTP_STATE, ct->head.set)) { 390 ret = __snprintf_protoinfo_sctp(buf+offset, len, ct); 391 BUFFER_SIZE(ret, size, len, offset); 392 } 393 394 if (test_bit(ATTR_DCCP_STATE, ct->head.set)) { 395 ret = __snprintf_protoinfo_dccp(buf+offset, len, ct); 396 BUFFER_SIZE(ret, size, len, offset); 397 } 398 399 ret = __snprintf_address(buf+offset, len, &ct->head.orig, 400 "src", "dst"); 401 BUFFER_SIZE(ret, size, len, offset); 402 403 ret = __snprintf_proto(buf+offset, len, &ct->head.orig); 404 BUFFER_SIZE(ret, size, len, offset); 405 406 if (test_bit(ATTR_ORIG_ZONE, ct->head.set)) { 407 ret = __snprintf_tuple_zone(buf+offset, len, "orig", &ct->head.orig); 408 BUFFER_SIZE(ret, size, len, offset); 409 } 410 411 if (test_bit(ATTR_ORIG_COUNTER_PACKETS, ct->head.set) && 412 test_bit(ATTR_ORIG_COUNTER_BYTES, ct->head.set)) { 413 ret = __snprintf_counters(buf+offset, len, ct, __DIR_ORIG); 414 BUFFER_SIZE(ret, size, len, offset); 415 } 416 417 if (test_bit(ATTR_STATUS, ct->head.set)) { 418 ret = __snprintf_status_not_seen_reply(buf+offset, len, ct); 419 BUFFER_SIZE(ret, size, len, offset); 420 } 421 422 ret = __snprintf_address(buf+offset, len, &ct->repl, 423 "src", "dst"); 424 BUFFER_SIZE(ret, size, len, offset); 425 426 ret = __snprintf_proto(buf+offset, len, &ct->repl); 427 BUFFER_SIZE(ret, size, len, offset); 428 429 if (test_bit(ATTR_REPL_ZONE, ct->head.set)) { 430 ret = __snprintf_tuple_zone(buf+offset, len, "reply", &ct->repl); 431 BUFFER_SIZE(ret, size, len, offset); 432 } 433 434 if (test_bit(ATTR_REPL_COUNTER_PACKETS, ct->head.set) && 435 test_bit(ATTR_REPL_COUNTER_BYTES, ct->head.set)) { 436 ret = __snprintf_counters(buf+offset, len, ct, __DIR_REPL); 437 BUFFER_SIZE(ret, size, len, offset); 438 } 439 440 if (test_bit(ATTR_STATUS, ct->head.set)) { 441 ret = __snprintf_status_assured(buf+offset, len, ct); 442 BUFFER_SIZE(ret, size, len, offset); 443 } 444 445 if (test_bit(ATTR_MARK, ct->head.set)) { 446 ret = __snprintf_mark(buf+offset, len, ct); 447 BUFFER_SIZE(ret, size, len, offset); 448 } 449 450 if (test_bit(ATTR_SECMARK, ct->head.set)) { 451 ret = __snprintf_secmark(buf+offset, len, ct); 452 BUFFER_SIZE(ret, size, len, offset); 453 } 454 455 if (test_bit(ATTR_SECCTX, ct->head.set)) { 456 ret = __snprintf_secctx(buf+offset, len, ct); 457 BUFFER_SIZE(ret, size, len, offset); 458 } 459 460 if (test_bit(ATTR_ZONE, ct->head.set)) { 461 ret = __snprintf_zone(buf+offset, len, ct); 462 BUFFER_SIZE(ret, size, len, offset); 463 } 464 465 if (test_bit(ATTR_TIMESTAMP_START, ct->head.set)) { 466 ret = __snprintf_timestamp_delta(buf+offset, len, ct); 467 BUFFER_SIZE(ret, size, len, offset); 468 } 469 if (flags & NFCT_OF_TIMESTAMP) { 470 if (test_bit(ATTR_TIMESTAMP_START, ct->head.set)) { 471 ret = __snprintf_timestamp_start(buf+offset, len, ct); 472 BUFFER_SIZE(ret, size, len, offset); 473 } 474 if (test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) { 475 ret = __snprintf_timestamp_stop(buf+offset, len, ct); 476 BUFFER_SIZE(ret, size, len, offset); 477 } 478 } 479 480 if (test_bit(ATTR_HELPER_NAME, ct->head.set)) { 481 ret = __snprintf_helper_name(buf+offset, len, ct); 482 BUFFER_SIZE(ret, size, len, offset); 483 } 484 485 if (test_bit(ATTR_USE, ct->head.set)) { 486 ret = __snprintf_use(buf+offset, len, ct); 487 BUFFER_SIZE(ret, size, len, offset); 488 } 489 490 if (flags & NFCT_OF_ID && test_bit(ATTR_ID, ct->head.set)) { 491 ret = __snprintf_id(buf+offset, len, ct); 492 BUFFER_SIZE(ret, size, len, offset); 493 } 494 495 if (map && test_bit(ATTR_CONNLABELS, ct->head.set)) { 496 ret = __snprintf_clabels(buf+offset, len, ct, map); 497 BUFFER_SIZE(ret, size, len, offset); 498 } 499 500 /* Delete the last blank space */ 501 size--; 502 503 return size; 504} 505