Ejemplo n.º 1
0
static int
gre_sre_asn_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
                  const u_char *bp, u_int len)
{
	const u_char *up = bp;

	if (sreoff & 1) {
		ND_PRINT(", badoffset=%u", sreoff);
		return (1);
	}
	if (srelen & 1) {
		ND_PRINT(", badlength=%u", srelen);
		return (1);
	}
	if (sreoff >= srelen) {
		ND_PRINT(", badoff/len=%u/%u", sreoff, srelen);
		return (1);
	}

	while (srelen != 0) {
		if (!ND_TTEST_2(bp))
			return (0);
		if (len < 2)
			return (0);

		ND_PRINT(" %s%x",
		    ((bp - up) == sreoff) ? "*" : "",
		    EXTRACT_BE_U_2(bp));

		bp += 2;
		len -= 2;
		srelen -= 2;
	}
	return (1);
}
Ejemplo n.º 2
0
static void
handle_mlppp(netdissect_options *ndo,
             const u_char *p, u_int length)
{
    if (!ndo->ndo_eflag)
        ND_PRINT("MLPPP, ");

    if (length < 2) {
        ND_PRINT("[|mlppp]");
        return;
    }
    if (!ND_TTEST_2(p)) {
        ND_PRINT("[|mlppp]");
        return;
    }

    ND_PRINT("seq 0x%03x, Flags [%s], length %u",
           (EXTRACT_BE_U_2(p))&0x0fff, /* only support 12-Bit sequence space for now */
           bittok2str(ppp_ml_flag_values, "none", EXTRACT_U_1(p) & 0xc0),
           length);
}
Ejemplo n.º 3
0
void
tcp_print(netdissect_options *ndo,
          const u_char *bp, u_int length,
          const u_char *bp2, int fragmented)
{
        const struct tcphdr *tp;
        const struct ip *ip;
        u_char flags;
        u_int hlen;
        char ch;
        uint16_t sport, dport, win, urp;
        uint32_t seq, ack, thseq, thack;
        u_int utoval;
        uint16_t magic;
        int rev;
        const struct ip6_hdr *ip6;

        ndo->ndo_protocol = "tcp";
        tp = (const struct tcphdr *)bp;
        ip = (const struct ip *)bp2;
        if (IP_V(ip) == 6)
                ip6 = (const struct ip6_hdr *)bp2;
        else
                ip6 = NULL;
        ch = '\0';
        if (!ND_TTEST_2(tp->th_dport)) {
                if (ip6) {
                        ND_PRINT("%s > %s:",
                                 ip6addr_string(ndo, ip6->ip6_src),
                                 ip6addr_string(ndo, ip6->ip6_dst));
                } else {
                        ND_PRINT("%s > %s:",
                                 ipaddr_string(ndo, ip->ip_src),
                                 ipaddr_string(ndo, ip->ip_dst));
                }
                nd_print_trunc(ndo);
                return;
        }

        sport = GET_BE_U_2(tp->th_sport);
        dport = GET_BE_U_2(tp->th_dport);

        if (ip6) {
                if (GET_U_1(ip6->ip6_nxt) == IPPROTO_TCP) {
                        ND_PRINT("%s.%s > %s.%s: ",
                                 ip6addr_string(ndo, ip6->ip6_src),
                                 tcpport_string(ndo, sport),
                                 ip6addr_string(ndo, ip6->ip6_dst),
                                 tcpport_string(ndo, dport));
                } else {
                        ND_PRINT("%s > %s: ",
                                 tcpport_string(ndo, sport), tcpport_string(ndo, dport));
                }
        } else {
                if (GET_U_1(ip->ip_p) == IPPROTO_TCP) {
                        ND_PRINT("%s.%s > %s.%s: ",
                                 ipaddr_string(ndo, ip->ip_src),
                                 tcpport_string(ndo, sport),
                                 ipaddr_string(ndo, ip->ip_dst),
                                 tcpport_string(ndo, dport));
                } else {
                        ND_PRINT("%s > %s: ",
                                 tcpport_string(ndo, sport), tcpport_string(ndo, dport));
                }
        }

        ND_TCHECK_SIZE(tp);

        hlen = TH_OFF(tp) * 4;

        if (hlen < sizeof(*tp)) {
                ND_PRINT(" tcp %u [bad hdr length %u - too short, < %lu]",
                         length - hlen, hlen, (unsigned long)sizeof(*tp));
                return;
        }

        seq = GET_BE_U_4(tp->th_seq);
        ack = GET_BE_U_4(tp->th_ack);
        win = GET_BE_U_2(tp->th_win);
        urp = GET_BE_U_2(tp->th_urp);

        if (ndo->ndo_qflag) {
                ND_PRINT("tcp %u", length - hlen);
                if (hlen > length) {
                        ND_PRINT(" [bad hdr length %u - too long, > %u]",
                                 hlen, length);
                }
                return;
        }

        flags = GET_U_1(tp->th_flags);
        ND_PRINT("Flags [%s]", bittok2str_nosep(tcp_flag_values, "none", flags));

        if (!ndo->ndo_Sflag && (flags & TH_ACK)) {
                /*
                 * Find (or record) the initial sequence numbers for
                 * this conversation.  (we pick an arbitrary
                 * collating order so there's only one entry for
                 * both directions).
                 */
                rev = 0;
                if (ip6) {
                        struct tcp_seq_hash6 *th;
                        struct tcp_seq_hash6 *tcp_seq_hash;
                        const void *src, *dst;
                        struct tha6 tha;

                        tcp_seq_hash = tcp_seq_hash6;
                        src = (const void *)ip6->ip6_src;
                        dst = (const void *)ip6->ip6_dst;
                        if (sport > dport)
                                rev = 1;
                        else if (sport == dport) {
                                if (UNALIGNED_MEMCMP(src, dst, sizeof(ip6->ip6_dst)) > 0)
                                        rev = 1;
                        }
                        if (rev) {
                                UNALIGNED_MEMCPY(&tha.src, dst, sizeof(ip6->ip6_dst));
                                UNALIGNED_MEMCPY(&tha.dst, src, sizeof(ip6->ip6_src));
                                tha.port = ((u_int)dport) << 16 | sport;
                        } else {
                                UNALIGNED_MEMCPY(&tha.dst, dst, sizeof(ip6->ip6_dst));
                                UNALIGNED_MEMCPY(&tha.src, src, sizeof(ip6->ip6_src));
                                tha.port = ((u_int)sport) << 16 | dport;
                        }

                        for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
                             th->nxt; th = th->nxt)
                                if (memcmp((char *)&tha, (char *)&th->addr,
                                           sizeof(th->addr)) == 0)
                                        break;

                        if (!th->nxt || (flags & TH_SYN)) {
                                /* didn't find it or new conversation */
                                /* calloc() return used by the 'tcp_seq_hash6'
                                   hash table: do not free() */
                                if (th->nxt == NULL) {
                                        th->nxt = (struct tcp_seq_hash6 *)
                                                calloc(1, sizeof(*th));
                                        if (th->nxt == NULL)
                                                (*ndo->ndo_error)(ndo,
                                                        S_ERR_ND_MEM_ALLOC,
                                                        "tcp_print: calloc");
                                }
                                th->addr = tha;
                                if (rev)
                                        th->ack = seq, th->seq = ack - 1;
                                else
                                        th->seq = seq, th->ack = ack - 1;
                        } else {
                                if (rev)
                                        seq -= th->ack, ack -= th->seq;
                                else
                                        seq -= th->seq, ack -= th->ack;
                        }

                        thseq = th->seq;
                        thack = th->ack;
                } else {
                        struct tcp_seq_hash *th;
                        struct tcp_seq_hash *tcp_seq_hash;
                        struct tha tha;

                        tcp_seq_hash = tcp_seq_hash4;
                        if (sport > dport)
                                rev = 1;
                        else if (sport == dport) {
                                if (UNALIGNED_MEMCMP(ip->ip_src, ip->ip_dst, sizeof(ip->ip_dst)) > 0)
                                        rev = 1;
                        }
                        if (rev) {
                                UNALIGNED_MEMCPY(&tha.src, ip->ip_dst,
                                                 sizeof(ip->ip_dst));
                                UNALIGNED_MEMCPY(&tha.dst, ip->ip_src,
                                                 sizeof(ip->ip_src));
                                tha.port = ((u_int)dport) << 16 | sport;
                        } else {
                                UNALIGNED_MEMCPY(&tha.dst, ip->ip_dst,
                                                 sizeof(ip->ip_dst));
                                UNALIGNED_MEMCPY(&tha.src, ip->ip_src,
                                                 sizeof(ip->ip_src));
                                tha.port = ((u_int)sport) << 16 | dport;
                        }

                        for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
                             th->nxt; th = th->nxt)
                                if (memcmp((char *)&tha, (char *)&th->addr,
                                           sizeof(th->addr)) == 0)
                                        break;

                        if (!th->nxt || (flags & TH_SYN)) {
                                /* didn't find it or new conversation */
                                /* calloc() return used by the 'tcp_seq_hash4'
                                   hash table: do not free() */
                                if (th->nxt == NULL) {
                                        th->nxt = (struct tcp_seq_hash *)
                                                calloc(1, sizeof(*th));
                                        if (th->nxt == NULL)
                                                (*ndo->ndo_error)(ndo,
                                                        S_ERR_ND_MEM_ALLOC,
                                                        "tcp_print: calloc");
                                }
                                th->addr = tha;
                                if (rev)
                                        th->ack = seq, th->seq = ack - 1;
                                else
                                        th->seq = seq, th->ack = ack - 1;
                        } else {
                                if (rev)
                                        seq -= th->ack, ack -= th->seq;
                                else
                                        seq -= th->seq, ack -= th->ack;
                        }

                        thseq = th->seq;
                        thack = th->ack;
                }
        } else {
                /*fool gcc*/
                thseq = thack = rev = 0;
        }
        if (hlen > length) {
                ND_PRINT(" [bad hdr length %u - too long, > %u]",
                         hlen, length);
                return;
        }

        if (ndo->ndo_vflag && !ndo->ndo_Kflag && !fragmented) {
                /* Check the checksum, if possible. */
                uint16_t sum, tcp_sum;

                if (IP_V(ip) == 4) {
                        if (ND_TTEST_LEN(tp->th_sport, length)) {
                                sum = tcp_cksum(ndo, ip, tp, length);
                                tcp_sum = GET_BE_U_2(tp->th_sum);

                                ND_PRINT(", cksum 0x%04x", tcp_sum);
                                if (sum != 0)
                                        ND_PRINT(" (incorrect -> 0x%04x)",
                                            in_cksum_shouldbe(tcp_sum, sum));
                                else
                                        ND_PRINT(" (correct)");
                        }
                } else if (IP_V(ip) == 6 && ip6->ip6_plen) {
                        if (ND_TTEST_LEN(tp->th_sport, length)) {
                                sum = tcp6_cksum(ndo, ip6, tp, length);
                                tcp_sum = GET_BE_U_2(tp->th_sum);

                                ND_PRINT(", cksum 0x%04x", tcp_sum);
                                if (sum != 0)
                                        ND_PRINT(" (incorrect -> 0x%04x)",
                                            in_cksum_shouldbe(tcp_sum, sum));
                                else
                                        ND_PRINT(" (correct)");

                        }
                }
        }

        length -= hlen;
        if (ndo->ndo_vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) {
                ND_PRINT(", seq %u", seq);

                if (length > 0) {
                        ND_PRINT(":%u", seq + length);
                }
        }

        if (flags & TH_ACK) {
                ND_PRINT(", ack %u", ack);
        }

        ND_PRINT(", win %u", win);

        if (flags & TH_URG)
                ND_PRINT(", urg %u", urp);
        /*
         * Handle any options.
         */
        if (hlen > sizeof(*tp)) {
                const u_char *cp;
                u_int i, opt, datalen;
                u_int len;

                hlen -= sizeof(*tp);
                cp = (const u_char *)tp + sizeof(*tp);
                ND_PRINT(", options [");
                while (hlen > 0) {
                        if (ch != '\0')
                                ND_PRINT("%c", ch);
                        ND_TCHECK_1(cp);
                        opt = GET_U_1(cp);
                        cp++;
                        if (ZEROLENOPT(opt))
                                len = 1;
                        else {
                                ND_TCHECK_1(cp);
                                len = GET_U_1(cp);
                                cp++;	/* total including type, len */
                                if (len < 2 || len > hlen)
                                        goto bad;
                                --hlen;		/* account for length byte */
                        }
                        --hlen;			/* account for type byte */
                        datalen = 0;

/* Bail if "l" bytes of data are not left or were not captured  */
#define LENCHECK(l) { if ((l) > hlen) goto bad; ND_TCHECK_LEN(cp, l); }


                        ND_PRINT("%s", tok2str(tcp_option_values, "unknown-%u", opt));

                        switch (opt) {

                        case TCPOPT_MAXSEG:
                                datalen = 2;
                                LENCHECK(datalen);
                                ND_PRINT(" %u", GET_BE_U_2(cp));
                                break;

                        case TCPOPT_WSCALE:
                                datalen = 1;
                                LENCHECK(datalen);
                                ND_PRINT(" %u", GET_U_1(cp));
                                break;

                        case TCPOPT_SACK:
                                datalen = len - 2;
                                if (datalen % 8 != 0) {
                                        ND_PRINT(" invalid sack");
                                } else {
                                        uint32_t s, e;

                                        ND_PRINT(" %u ", datalen / 8);
                                        for (i = 0; i < datalen; i += 8) {
                                                LENCHECK(i + 4);
                                                s = GET_BE_U_4(cp + i);
                                                LENCHECK(i + 8);
                                                e = GET_BE_U_4(cp + i + 4);
                                                if (rev) {
                                                        s -= thseq;
                                                        e -= thseq;
                                                } else {
                                                        s -= thack;
                                                        e -= thack;
                                                }
                                                ND_PRINT("{%u:%u}", s, e);
                                        }
                                }
                                break;

                        case TCPOPT_CC:
                        case TCPOPT_CCNEW:
                        case TCPOPT_CCECHO:
                        case TCPOPT_ECHO:
                        case TCPOPT_ECHOREPLY:

                                /*
                                 * those options share their semantics.
                                 * fall through
                                 */
                                datalen = 4;
                                LENCHECK(datalen);
                                ND_PRINT(" %u", GET_BE_U_4(cp));
                                break;

                        case TCPOPT_TIMESTAMP:
                                datalen = 8;
                                LENCHECK(datalen);
                                ND_PRINT(" val %u ecr %u",
                                             GET_BE_U_4(cp),
                                             GET_BE_U_4(cp + 4));
                                break;

                        case TCPOPT_SIGNATURE:
                                datalen = TCP_SIGLEN;
                                LENCHECK(datalen);
                                ND_PRINT(" ");
#ifdef HAVE_LIBCRYPTO
                                switch (tcp_verify_signature(ndo, ip, tp,
                                                             bp + TH_OFF(tp) * 4, length, cp)) {

                                case SIGNATURE_VALID:
                                        ND_PRINT("valid");
                                        break;

                                case SIGNATURE_INVALID:
                                        nd_print_invalid(ndo);
                                        break;

                                case CANT_CHECK_SIGNATURE:
                                        ND_PRINT("can't check - ");
                                        for (i = 0; i < TCP_SIGLEN; ++i)
                                                ND_PRINT("%02x",
                                                         GET_U_1(cp + i));
                                        break;
                                }
#else
                                for (i = 0; i < TCP_SIGLEN; ++i)
                                        ND_PRINT("%02x", GET_U_1(cp + i));
#endif
                                break;

                        case TCPOPT_SCPS:
                                datalen = 2;
                                LENCHECK(datalen);
                                ND_PRINT(" cap %02x id %u", GET_U_1(cp),
                                         GET_U_1(cp + 1));
                                break;

                        case TCPOPT_TCPAO:
                                datalen = len - 2;
                                /* RFC 5925 Section 2.2:
                                 * "The Length value MUST be greater than or equal to 4."
                                 * (This includes the Kind and Length fields already processed
                                 * at this point.)
                                 */
                                if (datalen < 2) {
                                        nd_print_invalid(ndo);
                                } else {
                                        LENCHECK(1);
                                        ND_PRINT(" keyid %u", GET_U_1(cp));
                                        LENCHECK(2);
                                        ND_PRINT(" rnextkeyid %u",
                                                 GET_U_1(cp + 1));
                                        if (datalen > 2) {
                                                ND_PRINT(" mac 0x");
                                                for (i = 2; i < datalen; i++) {
                                                        LENCHECK(i + 1);
                                                        ND_PRINT("%02x",
                                                                 GET_U_1(cp + i));
                                                }
                                        }
                                }
                                break;

                        case TCPOPT_EOL:
                        case TCPOPT_NOP:
                        case TCPOPT_SACKOK:
                                /*
                                 * Nothing interesting.
                                 * fall through
                                 */
                                break;

                        case TCPOPT_UTO:
                                datalen = 2;
                                LENCHECK(datalen);
                                utoval = GET_BE_U_2(cp);
                                ND_PRINT(" 0x%x", utoval);
                                if (utoval & 0x0001)
                                        utoval = (utoval >> 1) * 60;
                                else
                                        utoval >>= 1;
                                ND_PRINT(" %u", utoval);
                                break;

                        case TCPOPT_MPTCP:
                                datalen = len - 2;
                                LENCHECK(datalen);
                                if (!mptcp_print(ndo, cp-2, len, flags))
                                        goto bad;
                                break;

                        case TCPOPT_FASTOPEN:
                                datalen = len - 2;
                                LENCHECK(datalen);
                                ND_PRINT(" ");
                                print_tcp_fastopen_option(ndo, cp, datalen, FALSE);
                                break;

                        case TCPOPT_EXPERIMENT2:
                                datalen = len - 2;
                                LENCHECK(datalen);
                                if (datalen < 2)
                                        goto bad;
                                /* RFC6994 */
                                magic = GET_BE_U_2(cp);
                                ND_PRINT("-");

                                switch(magic) {

                                case 0xf989: /* TCP Fast Open RFC 7413 */
                                        print_tcp_fastopen_option(ndo, cp + 2, datalen - 2, TRUE);
                                        break;

                                default:
                                        /* Unknown magic number */
                                        ND_PRINT("%04x", magic);
                                        break;
                                }
                                break;

                        default:
                                datalen = len - 2;
                                if (datalen)
                                        ND_PRINT(" 0x");
                                for (i = 0; i < datalen; ++i) {
                                        LENCHECK(i + 1);
                                        ND_PRINT("%02x", GET_U_1(cp + i));
                                }
                                break;
                        }

                        /* Account for data printed */
                        cp += datalen;
                        hlen -= datalen;

                        /* Check specification against observed length */
                        ++datalen;		/* option octet */
                        if (!ZEROLENOPT(opt))
                                ++datalen;	/* size octet */
                        if (datalen != len)
                                ND_PRINT("[len %u]", len);
                        ch = ',';
                        if (opt == TCPOPT_EOL)
                                break;
                }
                ND_PRINT("]");
        }