]> granicus.if.org Git - strace/commitdiff
sockaddr: decode AX.25 socket addresses
authorEugene Syromyatnikov <evgsyr@gmail.com>
Mon, 27 Aug 2018 01:13:04 +0000 (03:13 +0200)
committerDmitry V. Levin <ldv@altlinux.org>
Sun, 2 Sep 2018 22:03:43 +0000 (22:03 +0000)
* defs.h (print_ax25_addr): New prototype.
* print_fields.h (PRINT_FIELD_AX25_ADDR): New macro.
* sockaddr.c: Include <linux/ax25.h>.
(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
print_fields.h
sockaddr.c
tests/net-sockaddr.c

diff --git a/defs.h b/defs.h
index ec96bf61138bdbf0401e6ac178cf2e88dbe05310..c4d271a0caa1cd8d6a54f3fe481285bd5e4a2211 100644 (file)
--- 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);
index 936db022fa8a8e4c4164753c1126622084ee3d70..c52d0ac073ff17d12e953fa6c05a0add59c7e1e6 100644 (file)
        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_))
index 2cf149f510aa0206fae18a7d9da304ff5d3b9a66..970991bcb3614f919408907990216d3359b207f8 100644 (file)
@@ -39,6 +39,7 @@
 #include <arpa/inet.h>
 
 #include "netlink.h"
+#include <linux/ax25.h>
 #include <linux/if_packet.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
@@ -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 },
index 22cbb265d256bc3e5714911b49b01ea94d507137..c84d8f01edde263fa91dfd4524ad14c9f9eecf65 100644 (file)
@@ -38,6 +38,7 @@
 #include <arpa/inet.h>
 #include <netinet/in.h>
 #include "netlink.h"
+#include <linux/ax25.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
@@ -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