From 92d020787fd5d55b3314b7ca54b0c5437c66d6c4 Mon Sep 17 00:00:00 2001 From: Eugene Syromyatnikov Date: Mon, 27 Aug 2018 03:13:04 +0200 Subject: [PATCH] sockaddr: decode AX.25 socket addresses * defs.h (print_ax25_addr): New prototype. * print_fields.h (PRINT_FIELD_AX25_ADDR): New macro. * sockaddr.c: Include . (check_ax25_address, ax25_addr2str, print_ax25_addr_raw, print_ax25_addr, print_sockaddr_data_ax25): New functions. (sa_printers) <[AF_AX25]>: New printer. * tests/net-sockaddr.c (AX25_ADDR): New macro. (check_ax25): New function. (main): Use it to check AX.25 socket address decoding. --- defs.h | 1 + print_fields.h | 6 ++ sockaddr.c | 160 +++++++++++++++++++++++++++++++++++++++++++ tests/net-sockaddr.c | 145 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 312 insertions(+) diff --git a/defs.h b/defs.h index ec96bf61..c4d271a0 100644 --- a/defs.h +++ b/defs.h @@ -891,6 +891,7 @@ print_inet_addr(int af, const void *addr, unsigned int len, const char *var_name extern bool decode_inet_addr(struct tcb *, kernel_ulong_t addr, unsigned int len, int family, const char *var_name); +extern void print_ax25_addr(const void /* ax25_address */ *addr); extern const char *get_sockaddr_by_inode(struct tcb *, int fd, unsigned long inode); extern bool print_sockaddr_by_inode(struct tcb *, int fd, unsigned long inode); extern void print_dirfd(struct tcb *, int); diff --git a/print_fields.h b/print_fields.h index 936db022..c52d0ac0 100644 --- a/print_fields.h +++ b/print_fields.h @@ -183,6 +183,12 @@ STRACE_PRINTF("%s%s=inet_addr(\"%s\")", (prefix_), #field_, \ inet_ntoa((where_).field_)) +#define PRINT_FIELD_AX25_ADDR(prefix_, where_, field_) \ + do { \ + STRACE_PRINTF("%s%s=", (prefix_), #field_); \ + print_ax25_addr(&(where_).field_); \ + } while (0) + #define PRINT_FIELD_NET_PORT(prefix_, where_, field_) \ STRACE_PRINTF("%s%s=htons(%u)", (prefix_), #field_, \ ntohs((where_).field_)) diff --git a/sockaddr.c b/sockaddr.c index 2cf149f5..970991bc 100644 --- a/sockaddr.c +++ b/sockaddr.c @@ -39,6 +39,7 @@ #include #include "netlink.h" +#include #include #include #include @@ -189,6 +190,164 @@ print_sockaddr_data_in6(const void *const buf, const int addrlen) PRINT_FIELD_U(", ", *sa_in6, sin6_scope_id); } +/** + * Check that we can print an AX.25 address in its native form, otherwise it + * makes sense to print it in raw also (or in raw only). + */ +enum xlat_style +check_ax25_address(const ax25_address *addr) +{ + enum xlat_style ret = XLAT_STYLE_DEFAULT; + bool space_seen = false; + bool char_seen = false; + + for (size_t i = 0; i < ARRAY_SIZE(addr->ax25_call) - 1; i++) { + unsigned char c = addr->ax25_call[i]; + + /* The lowest bit should be zero */ + if (c & 1) + ret = XLAT_STYLE_VERBOSE; + + c >>= 1; + + if (c == ' ') + space_seen = true; + else + char_seen = true; + + /* Sane address contains only numbers and uppercase letters */ + if ((c < '0' || c > '9') && (c < 'A' || c > 'Z') && c != ' ') + ret = XLAT_STYLE_VERBOSE; + if (c != ' ' && space_seen) + ret = XLAT_STYLE_VERBOSE; + + /* non-printable chars */ + if (c < ' ' || c > 0x7e + /* characters used for printing comments */ + || c == '*' || c == '/') + return XLAT_STYLE_RAW; + } + + if (addr->ax25_call[ARRAY_SIZE(addr->ax25_call) - 1] & ~0x1e) + ret = XLAT_STYLE_VERBOSE; + + if (!char_seen && addr->ax25_call[ARRAY_SIZE(addr->ax25_call) - 1]) + ret = XLAT_STYLE_VERBOSE; + + return ret; +} + +/** Convert a (presumably) valid AX.25 to a string */ +static const char * +ax25_addr2str(const ax25_address *addr) +{ + static char buf[ARRAY_SIZE(addr->ax25_call) + sizeof("-15")]; + char *p = buf; + size_t end; + + for (end = ARRAY_SIZE(addr->ax25_call) - 1; end; end--) + if ((addr->ax25_call[end - 1] >> 1) != ' ') + break; + + for (size_t i = 0; i < end; i++) + *p++ = ((unsigned char) addr->ax25_call[i]) >> 1; + + *p++ = '-'; + + unsigned char ssid = (addr->ax25_call[ARRAY_SIZE(addr->ax25_call) - 1] + >> 1) & 0xf; + + if (ssid > 9) { + *p++ = '1'; + ssid -= 10; + } + + *p++ = ssid + '0'; + *p = '\0'; + + if (buf[0] == '-' && buf[1] == '0') + return "*"; + + return buf; +} + +static void +print_ax25_addr_raw(const ax25_address *addr) +{ + PRINT_FIELD_HEX_ARRAY("{", *addr, ax25_call); + tprints("}"); +} + +void +print_ax25_addr(const void /* ax25_address */ *addr_void) +{ + const ax25_address *addr = addr_void; + enum xlat_style xs = check_ax25_address(addr); + + if (xs == XLAT_STYLE_DEFAULT) + xs = xlat_verbose(xlat_verbosity); + + if (xs != XLAT_STYLE_ABBREV) + print_ax25_addr_raw(addr); + + if (xs == XLAT_STYLE_RAW) + return; + + const char *addr_str = ax25_addr2str(addr); + + (xs == XLAT_STYLE_VERBOSE ? tprints_comment : tprints)(addr_str); +} + +static void +print_sockaddr_data_ax25(const void *const buf, const int addrlen) +{ + const struct full_sockaddr_ax25 *const sax25 = buf; + size_t addrlen_us = MAX(addrlen, 0); + bool full = sax25->fsa_ax25.sax25_ndigis || + (addrlen_us > sizeof(struct sockaddr_ax25)); + + if (full) + tprints("fsa_ax25={"); + + tprints("sax25_call="); + print_ax25_addr(&sax25->fsa_ax25.sax25_call); + PRINT_FIELD_D(", ", sax25->fsa_ax25, sax25_ndigis); + + if (!full) + return; + + tprints("}"); + + size_t has_digis = MIN((addrlen_us - sizeof(sax25->fsa_ax25)) + / sizeof(sax25->fsa_digipeater[0]), + ARRAY_SIZE(sax25->fsa_digipeater)); + size_t want_digis = MIN( + (unsigned int) MAX(sax25->fsa_ax25.sax25_ndigis, 0), + ARRAY_SIZE(sax25->fsa_digipeater)); + size_t digis = MIN(has_digis, want_digis); + + if (want_digis == 0) + goto digis_end; + + tprints(", fsa_digipeater=["); + for (size_t i = 0; i < digis; i++) { + if (i) + tprints(", "); + + print_ax25_addr(sax25->fsa_digipeater + i); + } + + if (want_digis > has_digis) + tprintf("%s/* ??? */", digis ? ", " : ""); + + tprints("]"); + +digis_end: + if (addrlen_us > (has_digis * sizeof(sax25->fsa_digipeater[0]) + + sizeof(sax25->fsa_ax25))) + tprints(", ..."); +} + static void print_sockaddr_data_ipx(const void *const buf, const int addrlen) { @@ -426,6 +585,7 @@ static const struct { } sa_printers[] = { [AF_UNIX] = { print_sockaddr_data_un, SIZEOF_SA_FAMILY + 1 }, [AF_INET] = { print_sockaddr_data_in, sizeof(struct sockaddr_in) }, + [AF_AX25] = { print_sockaddr_data_ax25, sizeof(struct sockaddr_ax25) }, [AF_IPX] = { print_sockaddr_data_ipx, sizeof(struct sockaddr_ipx) }, [AF_INET6] = { print_sockaddr_data_in6, SIN6_MIN_LEN }, [AF_NETLINK] = { print_sockaddr_data_nl, SIZEOF_SA_FAMILY + 1 }, diff --git a/tests/net-sockaddr.c b/tests/net-sockaddr.c index 22cbb265..c84d8f01 100644 --- a/tests/net-sockaddr.c +++ b/tests/net-sockaddr.c @@ -38,6 +38,7 @@ #include #include #include "netlink.h" +#include #include #include #include @@ -289,6 +290,149 @@ check_ipx(void) c_ipx.sipx_type, len, ret); } +/* for a bit more compact AX.25 address definitions */ +#define AX25_ADDR(c_, s_) \ + { { (c_)[0] << 1, (c_)[1] << 1, (c_)[2] << 1, \ + (c_)[3] << 1, (c_)[4] << 1, (c_)[5] << 1, (s_) << 1 } } \ + /* End of AX25_ADDR definition */ + +static void +check_ax25(void) +{ + const struct full_sockaddr_ax25 ax25 = { + .fsa_ax25 = { + .sax25_family = AF_AX25, + .sax25_call = AX25_ADDR("VALID ", 13), + .sax25_ndigis = 8, + }, + .fsa_digipeater = { + AX25_ADDR("SPA CE", 0), + AX25_ADDR("SSID ", 16), + AX25_ADDR(" ", 0), + AX25_ADDR("NULL\0", 3), + AX25_ADDR("A-B-C", 4), + AX25_ADDR(",}]\"\\'", 5), + AX25_ADDR("DASH-0", 6), + AX25_ADDR("\n\tABCD", 7), + }, + }; + const ax25_address aux_addrs[] = { + AX25_ADDR("VALID2", 7), + AX25_ADDR("OK ", 15), + AX25_ADDR("FINE ", 2), + AX25_ADDR("smalls", 9), + }; + + enum { AX25_ALIGN = ALIGNOF(struct full_sockaddr_ax25), }; + size_t size = sizeof(ax25); + size_t surplus = ROUNDUP(sizeof(ax25_address), AX25_ALIGN); + void *sax_void = midtail_alloc(size, surplus); + struct full_sockaddr_ax25 *sax = sax_void; + long rc; + + fill_memory(sax, size); + sax->fsa_ax25.sax25_family = AF_AX25; + rc = connect(-1, sax_void, sizeof(struct sockaddr_ax25) - 1); + printf("connect(-1, {sa_family=AF_AX25, sa_data=\"\\202\\203\\204\\205" + "\\206\\207\\210\\211\\212\\213\\214\\215\\216\"}, %zu) = %s\n", + sizeof(struct sockaddr_ax25) - 1, sprintrc(rc)); + + memcpy(sax, &ax25, sizeof(ax25)); + rc = connect(-1, sax_void, sizeof(struct sockaddr_ax25)); + printf("connect(-1, {sa_family=AF_AX25, fsa_ax25={sax25_call=VALID-13" + ", sax25_ndigis=8}, fsa_digipeater=[/* ??? */]}, %zu) = %s\n", + sizeof(struct sockaddr_ax25), sprintrc(rc)); + + sax->fsa_ax25.sax25_ndigis = 0; + rc = connect(-1, sax_void, sizeof(struct sockaddr_ax25)); + printf("connect(-1, {sa_family=AF_AX25, sax25_call=VALID-13" + ", sax25_ndigis=0}, %zu) = %s\n", + sizeof(struct sockaddr_ax25), sprintrc(rc)); + + sax->fsa_ax25.sax25_ndigis = 8; + size = sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 3 + 1; + rc = connect(-1, sax_void, size); + printf("connect(-1, {sa_family=AF_AX25, fsa_ax25={sax25_call=VALID-13" + ", sax25_ndigis=8}, fsa_digipeater" + "=[{ax25_call=\"\\xa6\\xa0\\x82\\x40\\x86\\x8a\\x00\"" + "} /* SPA CE-0 */" + ", {ax25_call=\"\\xa6\\xa6\\x92\\x88\\x40\\x40\\x20\"" + "} /* SSID-0 */" + ", *" + ", /* ??? */], ...}, %zu) = %s\n", + size, sprintrc(rc)); + + sax->fsa_digipeater[2].ax25_call[6] = 0x4; + size = sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 4; + rc = connect(-1, sax_void, size); + printf("connect(-1, {sa_family=AF_AX25, fsa_ax25={sax25_call=VALID-13" + ", sax25_ndigis=8}, fsa_digipeater" + "=[{ax25_call=\"\\xa6\\xa0\\x82\\x40\\x86\\x8a\\x00\"" + "} /* SPA CE-0 */" + ", {ax25_call=\"\\xa6\\xa6\\x92\\x88\\x40\\x40\\x20\"" + "} /* SSID-0 */" + ", {ax25_call=\"\\x40\\x40\\x40\\x40\\x40\\x40\\x04\"} /* -2 */" + ", {ax25_call=\"\\x9c\\xaa\\x98\\x98\\x00\\x00\\x06\"}" + ", /* ??? */]}, %zu) = %s\n", + size, sprintrc(rc)); + + memcpy(sax->fsa_digipeater, aux_addrs, sizeof(aux_addrs)); + sax->fsa_digipeater[2].ax25_call[6] = 0xa5; + sax->fsa_digipeater[4].ax25_call[5] = 0x40; + for (size_t i = 0; i < 3; i++) { + size = sizeof(ax25) + sizeof(ax25_address) * (i / 2); + rc = connect(-1, sax_void, size); + printf("connect(-1, {sa_family=AF_AX25" + ", fsa_ax25={sax25_call=VALID-13, sax25_ndigis=%d}" + ", fsa_digipeater=[VALID2-7, OK-15, %s /* FINE-2 */" + ", {ax25_call=\"\\xe6\\xda\\xc2\\xd8\\xd8\\xe6\\x12\"" + "} /* smalls-9 */" + ", {ax25_call=\"\\x%s\\x%s\\x84\\x5a\\x86\\x40\\x08\"" + "} /* %sB-C-4 */" + ", {ax25_call=\"\\x58\\xfa\\xba\\x44\\x%s\\x%s\\x0a\"" + "}%s" + ", {ax25_call=\"\\x88\\x82\\xa6\\x90\\x5a\\x%s\\x0c\"" + "}%s" + "%s]%s}, %zu) = %s\n" + , sax->fsa_ax25.sax25_ndigis + , i + ? "{ax25_call=\"\\x8c\\x92\\x9c\\x8a\\x40\\x41\\x04\"}" + : "{ax25_call=\"\\x8c\\x92\\x9c\\x8a\\x40\\x40\\xa5\"}" + , i ? "40" : "82" + , i ? "40" : "5a" + , i ? " " : "A-" + , i ? "54" : "b8" + , i ? "5e" : "4e" + , i ? "" : " /* ,}]\"\\'-5 */" + , i ? "fe" : "60" + , i ? "" : " /* DASH-0-6 */" + , i == 1 + ? "" + : ", {ax25_call=\"\\x14\\x12\\x82\\x84\\x86\\x88\\x0e\"}" + , i > 1 ? ", ..." : "" + , size, sprintrc(rc)); + + if (i == 1) { + sax_void = (char *) sax_void - surplus; + memmove(sax_void, sax, sizeof(ax25)); + sax = sax_void; + } + + sax->fsa_ax25.sax25_ndigis = 7 + 2 * i; + + sax->fsa_digipeater[2].ax25_call[5] = 0x41; + sax->fsa_digipeater[2].ax25_call[6] = 0x4; + + sax->fsa_digipeater[4].ax25_call[0] = 0x40; + sax->fsa_digipeater[4].ax25_call[1] = 0x40; + + sax->fsa_digipeater[5].ax25_call[4] = '*' << 1; + sax->fsa_digipeater[5].ax25_call[5] = '/' << 1; + + sax->fsa_digipeater[6].ax25_call[5] = 0xfe; + } +} + static void check_nl(void) { @@ -554,6 +698,7 @@ main(void) check_in(); check_in6(); check_ipx(); + check_ax25(); check_nl(); check_ll(); #ifdef HAVE_BLUETOOTH_BLUETOOTH_H