diff options
author | Jakub Zawadzki <darkjames-ws@darkjames.pl> | 2011-05-05 20:48:21 +0000 |
---|---|---|
committer | Jakub Zawadzki <darkjames-ws@darkjames.pl> | 2011-05-05 20:48:21 +0000 |
commit | 453d0a85686e332798ba43164c60947abfbefbd0 (patch) | |
tree | 584ed98bf2f60e687b9c4d09ebc01dd05457d455 | |
parent | 1792f8e3a6e8baba0e95e3719e0c862cb38ac106 (diff) |
Introduce ip6_to_str_buf_len (little cleaner version of inet_ntop6 from wsutil/inet_ntop.c)
and use it instead of inet_ntop(AF_INET6, ...)
- Add MAX_IP6_STR_LEN define.
- use MAX_IP6_STR_LEN as a buffer size when ip6_to_str_buf() is used.
svn path=/trunk/; revision=37000
-rw-r--r-- | epan/addr_resolv.c | 2 | ||||
-rw-r--r-- | epan/address_to_str.c | 101 | ||||
-rw-r--r-- | epan/to_str.c | 16 | ||||
-rw-r--r-- | epan/to_str.h | 1 |
4 files changed, 110 insertions, 10 deletions
diff --git a/epan/addr_resolv.c b/epan/addr_resolv.c index 0a6fb45215..8b662f7bb8 100644 --- a/epan/addr_resolv.c +++ b/epan/addr_resolv.c @@ -173,7 +173,7 @@ typedef struct hashipv6 { gboolean is_dummy_entry; /* name is IPv6 address in colon format */ gboolean resolve; /* */ struct hashipv6 *next; - gchar ip6[47]; /* XX */ + gchar ip6[MAX_IP6_STR_LEN]; /* XX */ gchar name[MAXNAMELEN]; } hashipv6_t; diff --git a/epan/address_to_str.c b/epan/address_to_str.c index 0beb50882c..cc212a40d0 100644 --- a/epan/address_to_str.c +++ b/epan/address_to_str.c @@ -66,6 +66,7 @@ /* private to_str.c API, don't export to .h! */ char *word_to_hex(char *out, guint16 word); +char *word_to_hex_npad(char *out, guint16 word); char *dword_to_hex_punct(char *out, guint32 dword, char punct); char *dword_to_hex(char *out, guint32 dword); char *bytes_to_hexstr(char *out, const guint8 *ad, guint32 len); @@ -126,13 +127,9 @@ remove this one later when every call has been converted to ep_address_to_str() */ gchar * ip6_to_str(const struct e_in6_addr *ad) { -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 46 -#endif gchar *str; - str=ep_alloc(INET6_ADDRSTRLEN+1); - + str=ep_alloc(MAX_IP6_STR_LEN); ip6_to_str_buf(ad, str); return str; } @@ -143,15 +140,102 @@ tvb_ip6_to_str(tvbuff_t *tvb, const gint offset) { gchar *buf; - buf=ep_alloc(INET6_ADDRSTRLEN+1); + buf=ep_alloc(MAX_IP6_STR_LEN); ip6_to_str_buf((const struct e_in6_addr *)tvb_get_ptr(tvb, offset, IPV6_LENGTH), buf); return buf; } +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static void +ip6_to_str_buf_len(const guchar* src, char *buf, size_t buf_len) +{ + struct { int base, len; } best, cur; + guint words[8]; + int i; + + if (buf_len < MAX_IP6_STR_LEN) { /* buf_len < 40 */ + g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len); /* Let the unexpected value alert user */ + return; + } + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + for (i = 0; i < 16; i += 2) { + words[i / 2] = (src[i+1] << 0); + words[i / 2] |= (src[i] << 8); + } + best.base = -1; + cur.base = -1; + for (i = 0; i < 8; i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* Is this address an encapsulated IPv4? */ + if (best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) + { + /* best.len == 6 -> ::IPv4; 5 -> ::ffff:IPv4 */ + buf = g_stpcpy(buf, "::"); + if (best.len == 5) + buf = g_stpcpy(buf, "ffff:"); + ip_to_str_buf(src + 12, buf, MAX_IP_STR_LEN); + /* max: 2 + 5 + 16 == 23 bytes */ + return; + } + + /* + * Format the result. + */ + for (i = 0; i < 8; i++) { + /* Are we inside the best run of 0x00's? */ + if (i == best.base) { + *buf++ = ':'; + i += best.len; + + /* Was it a trailing run of 0x00's? */ + if (i == 8) { + *buf++ = ':'; + break; + } + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *buf++ = ':'; + + buf = word_to_hex_npad(buf, words[i]); /* max: 4B */ + /* max: 8 * 4 + 7 == 39 bytes */ + } + *buf = '\0'; /* 40 byte */ +} + void ip6_to_str_buf(const struct e_in6_addr *ad, gchar *buf) { - inet_ntop(AF_INET6, (const guchar*)ad, buf, INET6_ADDRSTRLEN); + ip6_to_str_buf_len((const guchar*)ad, buf, MAX_IP6_STR_LEN); } gchar* @@ -393,8 +477,7 @@ address_to_str_buf(const address *addr, gchar *buf, int buf_len) ip_to_str_buf(addr->data, buf, buf_len); break; case AT_IPv6: - if ( inet_ntop(AF_INET6, addr->data, buf, buf_len) == NULL ) /* Returns NULL if no space and does not touch buf */ - g_snprintf ( buf, buf_len, BUF_TOO_SMALL_ERR ); /* Let the unexpected value alert user */ + ip6_to_str_buf_len(addr->data, buf, buf_len); break; case AT_IPX: /* 22 bytes */ addrdata = addr->data; diff --git a/epan/to_str.c b/epan/to_str.c index 8afa03eec4..ca7152f9c1 100644 --- a/epan/to_str.c +++ b/epan/to_str.c @@ -67,6 +67,22 @@ word_to_hex(char *out, guint16 word) { } char * +word_to_hex_npad(char *out, guint16 word) { + static const gchar hex_digits[16] = + { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + if (word >= 0x1000) + *out++ = hex_digits[(word >> 12) & 0xF]; + if (word >= 0x0100) + *out++ = hex_digits[(word >> 8) & 0xF]; + if (word >= 0x0010) + *out++ = hex_digits[(word >> 4) & 0xF]; + *out++ = hex_digits[word & 0xF]; + return out; +} + +char * dword_to_hex(char *out, guint32 dword) { out = byte_to_hex(out, dword >> 24); out = byte_to_hex(out, dword >> 16); diff --git a/epan/to_str.h b/epan/to_str.h index 5526f8b5d0..9467c4ee4d 100644 --- a/epan/to_str.h +++ b/epan/to_str.h @@ -33,6 +33,7 @@ #define GUID_STR_LEN 37 #define MAX_IP_STR_LEN 16 +#define MAX_IP6_STR_LEN 40 #define MAX_ADDR_STR_LEN 256 #define VINES_ADDR_LEN 6 |