📄 _pim.c
字号:
/*
* Copyright (c) 1995, 1996
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the University of California,
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#if 0
static const char rcsid[] =
"@(#) $Header: /tcpdump/master/tcpdump/print-pim.c,v 1.15.2.1 2000/01/25 18:29:05 itojun Exp $ (LBL)";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include "interfac.h"
#include "a2name.h"
#include "extract.h"
/*
* XXX: We consider a case where IPv6 is not ready yet for portability,
* but PIM dependent defintions should be independent of IPv6...
*/
struct pim
{
u_int8_t pim_typever;
/* upper 4bit: the PIM message type, currently they are:
* Hello, Register, Register-Stop, Join/Prune,
* Bootstrap, Assert, Graft (PIM-DM only),
* Graft-Ack (PIM-DM only), C-RP-Adv
*/
/* lower 4bit: PIM version number; 2 for PIMv2
*/
#define PIM_TYPE(x) (((x) & 0xf0) >> 4)
#define PIM_VER(x) ((x) & 0x0f)
u_char pim_rsv; /* Reserved */
u_short pim_cksum; /* IP style check sum */
};
static void pimv2_print (const u_char * bp, u_int len);
static void pimv1_join_prune_print (const u_char * bp, u_int len)
{
int maddrlen, addrlen, ngroups, njoin, nprune;
int njp;
/* If it's a single group and a single source, use 1-line output. */
if (TTEST2 (bp[0], 30) && bp[11] == 1 && ((njoin = EXTRACT_16BITS (&bp[20])) + EXTRACT_16BITS (&bp[22])) == 1)
{
int hold;
PRINTF (" RPF %s ", ipaddr_string (bp));
hold = EXTRACT_16BITS (&bp[6]);
if (hold != 180)
{
PUTS ("Hold ");
relts_print (hold);
}
PRINTF ("%s (%s/%d, %s", njoin ? "Join" : "Prune",
ipaddr_string (&bp[26]), bp[25] & 0x3f,
ipaddr_string (&bp[12]));
if (EXTRACT_32BITS (&bp[16]) != 0xffffffff)
PRINTF ("/%s", ipaddr_string (&bp[16]));
PRINTF (") %s%s %s",
(bp[24] & 0x01) ? "Sparse" : "Dense",
(bp[25] & 0x80) ? " WC" : "",
(bp[25] & 0x40) ? "RP" : "SPT");
return;
}
TCHECK2 (bp[0], 4);
PRINTF ("\n Upstream Nbr: %s", ipaddr_string (bp));
TCHECK2 (bp[6], 2);
PUTS ("\n Hold time: ");
relts_print (EXTRACT_16BITS (&bp[6]));
bp += 8;
len -= 8;
TCHECK2 (bp[0], 4);
maddrlen = bp[1];
addrlen = bp[2];
ngroups = bp[3];
bp += 4;
len -= 4;
while (ngroups--)
{
TCHECK2 (bp[0], 4);
PRINTF ("\n\tGroup: %s", ipaddr_string (bp));
if (EXTRACT_32BITS (&bp[4]) != 0xffffffff)
PRINTF ("/%s", ipaddr_string (&bp[4]));
TCHECK2 (bp[8], 4);
njoin = EXTRACT_16BITS (&bp[8]);
nprune = EXTRACT_16BITS (&bp[10]);
PRINTF (" joined: %d pruned: %d", njoin, nprune);
bp += 12;
len -= 12;
for (njp = 0; njp < (njoin + nprune); njp++)
{
char *type;
if (njp < njoin)
type = "Join ";
else type = "Prune";
TCHECK2 (bp[0], 6);
PRINTF ("\n\t%s %s%s%s%s/%d", type,
(bp[0] & 0x01) ? "Sparse " : "Dense ",
(bp[1] & 0x80) ? "WC " : "",
(bp[1] & 0x40) ? "RP " : "SPT ",
ipaddr_string (&bp[2]), bp[1] & 0x3f);
bp += 6;
len -= 6;
}
}
return;
trunc:
PUTS ("[|pim]");
}
void pimv1_print (const u_char * bp, u_int len)
{
const u_char *ep = (const u_char *) snapend;
u_char type;
if (bp >= ep)
return;
type = bp[1];
switch (type)
{
case 0:
PUTS (" Query");
if (TTEST (bp[8]))
{
switch (bp[8] >> 4)
{
case 0:
PUTS (" Dense-mode");
break;
case 1:
PUTS (" Sparse-mode");
break;
case 2:
PUTS (" Sparse-Dense-mode");
break;
default:
PRINTF (" mode-%d", bp[8] >> 4);
break;
}
}
if (vflag)
{
TCHECK2 (bp[10], 2);
PUTS (" (Hold-time ");
relts_print (EXTRACT_16BITS (&bp[10]));
PUTCHAR (')');
}
break;
case 1:
PUTS (" Register");
TCHECK2 (bp[8], 20); /* ip header */
PRINTF (" for %s > %s",
ipaddr_string (&bp[20]),
ipaddr_string (&bp[24]));
break;
case 2:
PUTS (" Register-Stop");
TCHECK2 (bp[12], 4);
PRINTF (" for %s > %s",
ipaddr_string (&bp[8]),
ipaddr_string (&bp[12]));
break;
case 3:
PUTS (" Join/Prune");
if (vflag)
pimv1_join_prune_print (&bp[8], len - 8);
break;
case 4:
PUTS (" RP-reachable");
if (vflag)
{
TCHECK2 (bp[22], 2);
PRINTF (" group %s", ipaddr_string (&bp[8]));
if (EXTRACT_32BITS (&bp[12]) != 0xffffffff)
PRINTF ("/%s", ipaddr_string (&bp[12]));
PRINTF (" RP %s hold ", ipaddr_string (&bp[16]));
relts_print (EXTRACT_16BITS (&bp[22]));
}
break;
case 5:
PUTS (" Assert");
TCHECK2 (bp[16], 4);
PRINTF (" for %s > %s",
ipaddr_string (&bp[16]),
ipaddr_string (&bp[8]));
if (EXTRACT_32BITS (&bp[12]) != 0xffffffff)
PRINTF ("/%s", ipaddr_string (&bp[12]));
TCHECK2 (bp[24], 4);
PRINTF (" %s pref %d metric %d",
(bp[20] & 0x80) ? "RP-tree" : "SPT",
EXTRACT_32BITS (&bp[20]) & 0x7fffffff,
EXTRACT_32BITS (&bp[24]));
break;
case 6:
PUTS (" Graft");
if (vflag)
pimv1_join_prune_print (&bp[8], len - 8);
break;
case 7:
PUTS (" Graft-ACK");
if (vflag)
pimv1_join_prune_print (&bp[8], len - 8);
break;
case 8:
PUTS (" Mode");
break;
default:
PRINTF (" [type %d]", type);
break;
}
if ((bp[4] >> 4) != 1)
PRINTF (" [v%d]", bp[4] >> 4);
return;
trunc:
PUTS ("[|pim]");
}
/*
* auto-RP is a cisco protocol, documented at
* ftp://ftpeng.cisco.com/ipmulticast/pim-autorp-spec01.txt
*/
void cisco_autorp_print (const u_char * bp, u_int len)
{
int type, numrps, hold;
TCHECK (bp[0]);
PUTS (" auto-rp ");
type = bp[0];
switch (type)
{
case 0x11:
PUTS ("candidate-advert");
break;
case 0x12:
PUTS ("mapping");
break;
default:
PRINTF ("type-0x%02x", type);
break;
}
TCHECK (bp[1]);
numrps = bp[1];
TCHECK2 (bp[2], 2);
PUTS (" Hold ");
hold = EXTRACT_16BITS (&bp[2]);
if (hold)
relts_print (EXTRACT_16BITS (&bp[2]));
else PUTS ("FOREVER");
/* Next 4 bytes are reserved.
*/
bp += 8;
len -= 8;
/* XXX skip unless -v? */
/*
* Rest of packet:
* numrps entries of the form:
* 32 bits: RP
* 6 bits: reserved
* 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
* 8 bits: # of entries for this RP
* each entry: 7 bits: reserved, 1 bit: negative,
* 8 bits: mask 32 bits: source
* lather, rinse, repeat.
*/
while (numrps--)
{
int nentries;
char s;
TCHECK2 (bp[0], 4);
PRINTF (" RP %s", ipaddr_string (bp));
TCHECK (bp[4]);
switch (bp[4] & 0x3)
{
case 0:
PUTS (" PIMv?");
break;
case 1:
PUTS (" PIMv1");
break;
case 2:
PUTS (" PIMv2");
break;
case 3:
PUTS (" PIMv1+2");
break;
}
TCHECK (bp[5]);
nentries = bp[5];
bp += 6;
len -= 6;
s = ' ';
for (; nentries; nentries--)
{
TCHECK2 (bp[0], 6);
PRINTF ("%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
ipaddr_string (&bp[2]), bp[1]);
s = ',';
bp += 6;
len -= 6;
}
}
return;
trunc:
PUTS ("[|autorp]");
}
void pim_print (const u_char * bp, u_int len)
{
const u_char *ep = (const u_char *) snapend;
struct pim *pim = (struct pim *) bp;
if (bp >= ep)
return;
#ifdef notyet /* currently we see only version and type */
TCHECK (pim->pim_rsv);
#endif
switch (PIM_VER (pim->pim_typever))
{
case 2: /* avoid hardcoding? */
PUTS ("v2");
pimv2_print (bp, len);
break;
default:
PRINTF ("v%d", PIM_VER (pim->pim_typever));
break;
}
}
/*
* PIMv2 uses encoded address representations.
*
* The last PIM-SM I-D before RFC2117 was published specified the
* following representation for unicast addresses. However, RFC2117
* specified no encoding for unicast addresses with the unicast
* address length specified in the header. Therefore, we have to
* guess which encoding is being used (Cisco's PIMv2 implementation
* uses the non-RFC encoding). RFC2117 turns a previously "Reserved"
* field into a 'unicast-address-length-in-bytes' field. We guess
* that it's the draft encoding if this reserved field is zero.
*
* RFC2362 goes back to the encoded format, and calls the addr length
* field "reserved" again.
*
* The first byte is the address family, from:
*
* 0 Reserved
* 1 IP (IP version 4)
* 2 IP6 (IP version 6)
* 3 NSAP
* 4 HDLC (8-bit multidrop)
* 5 BBN 1822
* 6 802 (includes all 802 media plus Ethernet "canonical format")
* 7 E.163
* 8 E.164 (SMDS, Frame Relay, ATM)
* 9 F.69 (Telex)
* 10 X.121 (X.25, Frame Relay)
* 11 IPX
* 12 Appletalk
* 13 Decnet IV
* 14 Banyan Vines
* 15 E.164 with NSAP format subaddress
*
* In addition, the second byte is an "Encoding". 0 is the default
* encoding for the address family, and no other encodings are currently
* specified.
*
*/
static int pimv2_addr_len;
enum pimv2_addrtype {
pimv2_unicast, pimv2_group, pimv2_source
};
#if 0
static char *addrtypestr[] = {
"unicast", "group", "source"
};
#endif
/* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Addr Family | Encoding Type | Unicast Address |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Addr Family | Encoding Type | Reserved | Mask Len |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Group multicast Address |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Addr Family | Encoding Type | Rsrvd |S|W|R| Mask Len |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Source Address |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
static int pimv2_addr_print (const u_char *bp, enum pimv2_addrtype at, int silent)
{
char *afstr;
int af, len, hdrlen;
TCHECK (bp[0]);
if (pimv2_addr_len == 0)
{
TCHECK (bp[1]);
switch (bp[0])
{
case 1:
af = AF_INET;
afstr = "IPv4";
len = 4;
break;
#ifdef USE_INET6
case 2:
af = AF_INET6;
afstr = "IPv6";
len = 16;
break;
#endif
default:
return -1;
}
if (bp[1] != 0)
return -1;
hdrlen = 2;
}
else
{
switch (pimv2_addr_len)
{
case 4:
af = AF_INET;
afstr = "IPv4";
break;
#ifdef USE_INET6
case 16:
af = AF_INET6;
afstr = "IPv6";
break;
#endif
default:
return -1;
}
len = pimv2_addr_len;
hdrlen = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -