From 5b8f338ecee33a4471924e65d685fde98134bc31 Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Mon, 3 Sep 2018 15:23:47 +0300 Subject: [PATCH] 9787 snoop: add tftp OACK support Reviewed by: Andy Fiddaman Reviewed by: Garrett D'Amore Approved by: Dan McDonald --- usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h | 19 +- usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c | 9 +- usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_slp.c | 14 +- usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_tftp.c | 232 +++++++++++++++------- 4 files changed, 186 insertions(+), 88 deletions(-) diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h index e4f182572b..d9c559dec1 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h @@ -69,6 +69,19 @@ extern "C" { #define MAXLINE (1088) /* max len of detail line */ /* + * Transient port structure. See TFTP interpreter. + */ +struct ttable { + int t_port; + int blksize; + int (*t_proc)(int, void *, int); +}; + +extern int add_transient(int port, int (*proc)(int, void *, int)); +extern struct ttable *is_transient(int port); +extern void del_transient(int port); + +/* * The RPC XID cache structure. * When analyzing RPC protocols we * have to cache the xid of the RPC @@ -243,14 +256,14 @@ struct dhcp; extern int interpret_dhcp(int, struct dhcp *, int); extern int interpret_dhcpv6(int, const uint8_t *, int); struct tftphdr; -extern int interpret_tftp(int, struct tftphdr *, int); +extern int interpret_tftp(int, void *, int); extern int interpret_http(int, char *, int); struct ntpdata; extern int interpret_ntp(int, struct ntpdata *, int); extern void interpret_netbios_ns(int, uchar_t *, int); extern void interpret_netbios_datagram(int, uchar_t *, int); extern void interpret_netbios_ses(int, uchar_t *, int); -extern void interpret_slp(int, char *, int); +extern void interpret_slp(int, void *, int); struct rip; extern int interpret_rip(int, struct rip *, int); struct rip6; @@ -293,7 +306,7 @@ typedef uint_t (headerlen_fn_t)(char *, size_t); typedef struct interface { uint_t mac_type; uint_t mtu_size; - uint_t network_type_offset; + uint_t network_type_offset; size_t network_type_len; uint_t network_type_ip; uint_t network_type_ipv6; diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c index b84ee3c1b4..3f745b30eb 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c @@ -179,13 +179,10 @@ reservedport(int proto, int port) * See TFTP interpreter. */ #define MAXTRANS 64 -static struct ttable { - int t_port; - int (*t_proc)(int, char *, int); -} transients [MAXTRANS]; +static struct ttable transients [MAXTRANS]; int -add_transient(int port, int (*proc)(int, char *, int)) +add_transient(int port, int (*proc)(int, void *, int)) { static struct ttable *next = transients; @@ -198,7 +195,7 @@ add_transient(int port, int (*proc)(int, char *, int)) return (1); } -static struct ttable * +struct ttable * is_transient(int port) { struct ttable *p; diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_slp.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_slp.c index 9feb3e9b27..fc0cd87522 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_slp.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_slp.c @@ -24,8 +24,6 @@ * All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -64,9 +62,6 @@ static int v2_finish(struct slpv2_hdr *, int); /* V2 auth blocks */ static int slpv2_authblock(int); -/* From snoop_rport: */ -extern int add_transient(int, int (*)()); - /* * Functions for parsing each protocol message * Each function takes the interpreter's flags argument as its input @@ -163,9 +158,10 @@ static char *slpv1_charset(unsigned short); * The only external entry point to the SLP interpreter. This function * simply dispatches the packet based on the version. */ -void interpret_slp(int flags, char *slp, int fraglen) { +void interpret_slp(int flags, void *slp, int fraglen) { extern int dst_port, curr_proto; struct tcp_cont *tce = NULL; + char *s; msglength = fraglen; retlength = 0; @@ -182,10 +178,10 @@ void interpret_slp(int flags, char *slp, int fraglen) { } } } - if (*slp == 2 || tce) - interpret_slp_v2(flags, (void *)slp, fraglen); + if (*(char *)slp == 2 || tce) + interpret_slp_v2(flags, slp, fraglen); else - interpret_slp_v1(flags, (void *)slp, fraglen); + interpret_slp_v1(flags, slp, fraglen); tcp_continuation = B_FALSE; } diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_tftp.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_tftp.c index 21964540fd..0c7b95cbe9 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_tftp.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_tftp.c @@ -24,22 +24,32 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include "snoop.h" +struct tftp_options { + int blksize; + int tsize; +}; + extern char *dlc_header; -char *tftperror(); -char *show_type(); +static char *tftperror(unsigned short); +static char *show_type(int); +static char *tftp_parse_oack(char *, size_t, struct tftp_options *); int -interpret_tftp(int flags, struct tftphdr *tftp, int fraglen) +interpret_tftp(int flags, void *data, int fraglen) { char *name, *mode; extern int src_port, dst_port; int blocksize = fraglen - 4; + struct tftp_options opts; + struct ttable *tt; + struct tftphdr *tftp = data; + + opts.tsize = 0; + opts.blksize = 512; switch (ntohs(tftp->th_opcode)) { case RRQ: @@ -49,6 +59,18 @@ interpret_tftp(int flags, struct tftphdr *tftp, int fraglen) case ERROR: del_transient(src_port); break; + case OACK: + tt = is_transient(dst_port); + if (tt != NULL) + tt->blksize = opts.blksize; + break; + case DATA: + tt = is_transient(dst_port); + if (tt != NULL) + opts.blksize = tt->blksize; + break; + default: + break; } if (flags & F_SUM) { @@ -57,94 +79,102 @@ interpret_tftp(int flags, struct tftphdr *tftp, int fraglen) name = (char *)&tftp->th_stuff; mode = name + (strlen(name) + 1); (void) sprintf(get_sum_line(), - "TFTP Read \"%s\" (%s)", name, mode); + "TFTP Read \"%s\" (%s)", name, mode); break; case WRQ: name = (char *)&tftp->th_stuff; mode = name + (strlen(name) + 1); (void) sprintf(get_sum_line(), - "TFTP Write \"%s\" (%s)", name, mode); + "TFTP Write \"%s\" (%s)", name, mode); break; case DATA: (void) sprintf(get_sum_line(), - "TFTP Data block %d (%d bytes)%s", - ntohs(tftp->th_block), - blocksize, - blocksize < 512 ? " (last block)":""); + "TFTP Data block %u (%d bytes)%s", + ntohs(tftp->th_block), blocksize, + blocksize < opts.blksize ? " (last block)":""); break; case ACK: - (void) sprintf(get_sum_line(), - "TFTP Ack block %d", - ntohs(tftp->th_block)); + (void) sprintf(get_sum_line(), "TFTP Ack block %d", + ntohs(tftp->th_block)); break; case ERROR: - (void) sprintf(get_sum_line(), - "TFTP Error: %s", - tftperror(ntohs(tftp->th_code))); + (void) sprintf(get_sum_line(), "TFTP Error: %s", + tftperror(ntohs(tftp->th_code))); + break; + case OACK: + (void) sprintf(get_sum_line(), "TFTP OACK: %s", + tftp_parse_oack((char *)&tftp->th_stuff, + fraglen - sizeof (tftp->th_opcode), &opts)); + if (tt != NULL) + tt->blksize = opts.blksize; break; } } if (flags & F_DTAIL) { + show_header("TFTP: ", "Trivial File Transfer Protocol", + fraglen); + show_space(); + (void) sprintf(get_line((char *)(uintptr_t)tftp->th_opcode - + dlc_header, 2), "Opcode = %d (%s)", ntohs(tftp->th_opcode), + show_type(ntohs(tftp->th_opcode))); - show_header("TFTP: ", "Trivial File Transfer Protocol", fraglen); - show_space(); - (void) sprintf(get_line((char *)(uintptr_t)tftp->th_opcode - - dlc_header, 2), - "Opcode = %d (%s)", - ntohs(tftp->th_opcode), - show_type(ntohs(tftp->th_opcode))); - - switch (ntohs(tftp->th_opcode)) { - case RRQ: - case WRQ: - name = (char *)&tftp->th_stuff; - mode = name + (strlen(name) + 1); - (void) sprintf( - get_line(name - dlc_header, strlen(name) + 1), - "File name = \"%s\"", - name); - (void) sprintf( - get_line(mode - dlc_header, strlen(mode) + 1), - "Transfer mode = %s", - mode); - break; + switch (ntohs(tftp->th_opcode)) { + case RRQ: + case WRQ: + name = (char *)&tftp->th_stuff; + mode = name + (strlen(name) + 1); + (void) sprintf( + get_line(name - dlc_header, strlen(name) + 1), + "File name = \"%s\"", name); + (void) sprintf( + get_line(mode - dlc_header, strlen(mode) + 1), + "Transfer mode = %s", mode); + break; - case DATA: - (void) sprintf( - get_line((char *)(uintptr_t)tftp->th_block - - dlc_header, 2), "Data block = %d%s", - ntohs(tftp->th_block), - blocksize < 512 ? " (last block)":""); - (void) sprintf(get_line((char *)(uintptr_t)tftp->th_data - - dlc_header, blocksize), - "[ %d bytes of data ]", - blocksize); - break; + case DATA: + (void) sprintf(get_line( + (char *)(uintptr_t)tftp->th_block - dlc_header, 2), + "Data block = %d%s", ntohs(tftp->th_block), + blocksize < opts.blksize ? " (last block)" : ""); + (void) sprintf(get_line( + (char *)(uintptr_t)tftp->th_data - dlc_header, + blocksize), "[ %d bytes of data ]", blocksize); + break; - case ACK: - (void) sprintf(get_line((char *)(uintptr_t)tftp->th_block - - dlc_header, 2), "Acknowledge block = %d", - ntohs(tftp->th_block)); - break; + case ACK: + (void) sprintf(get_line( + (char *)(uintptr_t)tftp->th_block - dlc_header, 2), + "Acknowledge block = %d", ntohs(tftp->th_block)); + break; - case ERROR: - (void) sprintf(get_line((char *)(uintptr_t)tftp->th_code - - dlc_header, 2), "Error = %d (%s)", - ntohs(tftp->th_code), - tftperror(ntohs(tftp->th_code))); - (void) sprintf(get_line((char *)(uintptr_t)tftp->th_data - - dlc_header, strlen(tftp->th_data) + 1), - "Error string = \"%s\"", tftp->th_data); - } + case ERROR: + (void) sprintf(get_line( + (char *)(uintptr_t)tftp->th_code - dlc_header, 2), + "Error = %d (%s)", ntohs(tftp->th_code), + tftperror(ntohs(tftp->th_code))); + (void) sprintf(get_line( + (char *)(uintptr_t)tftp->th_data - + dlc_header, strlen(tftp->th_data) + 1), + "Error string = \"%s\"", tftp->th_data); + break; + case OACK: + (void) sprintf(get_line( + (char *)(uintptr_t)tftp->th_code - dlc_header, 2), + "TFTP OACK: %s", + tftp_parse_oack((char *)&tftp->th_stuff, + fraglen - sizeof (tftp->th_opcode), &opts)); + if (tt != NULL) + tt->blksize = opts.blksize; + break; + } } return (fraglen); } -char * -show_type(t) - int t; +static char * +show_type(int t) { switch (t) { case RRQ: return ("read request"); @@ -152,13 +182,13 @@ show_type(t) case DATA: return ("data packet"); case ACK: return ("acknowledgement"); case ERROR: return ("error"); + case OACK: return ("option acknowledgement"); } return ("?"); } -char * -tftperror(code) - unsigned short code; +static char * +tftperror(unsigned short code) { static char buf[128]; @@ -176,3 +206,65 @@ tftperror(code) return (buf); } + +static char * +tftp_parse_oack(char *buf, size_t size, struct tftp_options *opts) +{ + static char tftp_options[128]; + int i, idx; + + tftp_options[0] = '\0'; + idx = 0; + + while (size > 0 && idx < sizeof (tftp_options)) { + if (idx > 0) { + tftp_options[idx++] = ' '; + tftp_options[idx] = '\0'; + } + + /* get name */ + if (idx + strnlen(buf, size) + 1 > sizeof (tftp_options)) + break; + for (i = 0; i < size; i++) { + tftp_options[idx] = buf[i]; + if (tftp_options[idx] == '\0') { + i++; + break; + } + idx++; + } + size -= i; + /* + * RFC 2348 requires this case in-sensitive. + */ + if (strcasecmp(buf, "blksize") == 0) { + int blksize = strtol(buf + i, NULL, 0); + + if (blksize >= 8) + opts->blksize = blksize; + } + buf += i; + + /* can we store separator? */ + if (idx + 3 > sizeof (tftp_options)) + break; + strcat(tftp_options, ": "); + idx += 2; + + /* get value */ + if (idx + strnlen(buf, size) + 1 > sizeof (tftp_options)) + break; + + for (i = 0; i < size; i++) { + tftp_options[idx] = buf[i]; + if (tftp_options[idx] == '\0') { + i++; + break; + } + idx++; + } + size -= i; + buf += i; + } + return (tftp_options); +} -- 2.11.4.GIT