1
0
Files
2022-09-29 17:59:04 +03:00

292 lines
6.7 KiB
C

/*
* Copyright 1990 Silicon Graphics, Inc. All rights reserved.
*
* User Datagram Protocol (UDP), defined in RFC 768.
*/
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include "index.h"
#include "protodefs.h"
#include "protocols/ip.h"
#include "protocols/sunrpc.h"
char udpname[] = "udp";
/*
* UDP field identifiers and descriptors.
*/
enum udpfid { SPORT=IPFID_SPORT, DPORT=IPFID_DPORT, LEN, SUM };
static ProtoField udpfields[] = {
PFI_UINT("sport", "Source Port", SPORT, u_short, PV_TERSE),
PFI_UINT("dport", "Destination Port", DPORT, u_short, PV_TERSE),
PFI_UINT("len", "Length", LEN, u_short, PV_VERBOSE),
PFI_UINT("sum", "Checksum", SUM, u_short, PV_VERBOSE),
};
#define UDPFID(pf) ((enum udpfid) (pf)->pf_id)
#define UDPFIELD(fid) udpfields[(int) fid]
static ProtoMacro udpnicknames[] = {
PMI("UDP", udpname),
PMI("nfs", "udp.sunrpc.nfs"),
PMI("NFS", "udp.sunrpc.nfs"),
};
static ProtoMacro udpmacros[] = {
PMI("between",
"sport == $1 && dport == $2 || dport == $1 && sport == $2"),
PMI("port", "sport == $1 || dport == $1"),
};
static ProtOptDesc udpoptdesc[] = {
POD("setport", UDP_PROPT_SETPORT,
"Map port number to protocol ([host:]port/protocol)"),
};
/*
* UDP protocol interface and operations.
*/
DefineProtocol(udp, udpname, "User Datagram Protocol", PRID_UDP,
DS_BIG_ENDIAN, sizeof(struct udphdr), 0,
0, udpoptdesc, lengthof(udpoptdesc), 0);
static Index *udpports;
static Protocol *sunrpc;
/*
* UDP protocol functions.
*/
/* ARGSUSED */
int
udp_func_badsum(Expr *argv, DataStream *ds, ProtoStack *ps, Expr *rex)
{
struct udphdr *uh;
u_short realsum, idealsum;
struct ipframe *ipf;
uh = (struct udphdr *) ds_inline(ds, sizeof *uh, IP_HDRGRAIN);
if (uh == 0)
return 0;
ipf = PS_TOP(ps, struct ipframe);
if (ipf == 0)
return 0;
realsum = uh->uh_sum;
if (realsum == 0)
return 0;
uh->uh_sum = 0;
if (!ip_checksum_pseudohdr(ipf, (char *) uh,
sizeof *uh + ds->ds_count, &idealsum)) {
uh->uh_sum = realsum;
return 0;
}
uh->uh_sum = realsum;
if (idealsum == 0)
idealsum = ~idealsum;
rex->ex_op = EXOP_NUMBER;
rex->ex_val = (ntohs(realsum) != idealsum);
return 1;
}
static ProtoFuncDesc udpfunctions[] = {
PFD("badsum", udp_func_badsum, 0,
"Match packet if UDP checksum is incorrect"),
};
static int
udp_init()
{
if (!pr_register(&udp_proto, udpfields, lengthof(udpfields),
lengthof(udpmacros) + 12)) {
return 0;
}
if (!pr_nest(&udp_proto, PRID_IP, IPPROTO_UDP, udpnicknames,
lengthof(udpnicknames))) {
return 0;
}
in_create(10, sizeof(u_short), 0, &udpports);
pr_addmacros(&udp_proto, udpmacros, lengthof(udpmacros));
pr_addfunctions(&udp_proto, udpfunctions, lengthof(udpfunctions));
return 1;
}
/* ARGSUSED */
static int
udp_setopt(int id, char *val)
{
if ((enum udp_propt) id != UDP_PROPT_SETPORT)
return 0;
return ip_setport(val, udp_embed);
}
static void
udp_embed(Protocol *pr, long prototype, long qualifier)
{
u_short port;
port = prototype;
if (pr->pr_id == PRID_SUNRPC)
sunrpc = pr;
in_enterqual(udpports, &port, pr, qualifier);
}
/* ARGSUSED */
static Expr *
udp_resolve(char *name, int len, struct snooper *sn)
{
struct servent *sp;
u_short port;
Expr *ex;
sp = getservbyname(name, udpname);
if (sp)
port = sp->s_port;
else if (!sunrpc_getport(name, IPPROTO_UDP, &port))
return 0;
ex = expr(EXOP_NUMBER, EX_NULLARY, name);
ex->ex_val = port;
return ex;
}
static ExprType
udp_compile(ProtoField *pf, Expr *mex, Expr *tex, ProtoCompiler *pc)
{
long mask;
if (!pc_intmask(pc, mex, &mask))
return ET_ERROR;
if (tex->ex_op != EXOP_NUMBER) {
pc_badop(pc, tex);
return ET_ERROR;
}
if (!pc_intfield(pc, pf, mask, tex->ex_val, sizeof(struct udphdr)))
return ET_COMPLEX;
return ET_SIMPLE;
}
/*
* Lookup port's protocol in udpports.
*/
static Protocol *
udp_findproto(u_short port, struct in_addr addr)
{
Protocol *pr;
pr = in_matchqual(udpports, &port, addr.s_addr);
if (pr)
return pr;
if (sunrpc_ismapped(port, addr, IPPROTO_UDP))
return sunrpc;
return 0;
}
static int
udp_match(Expr *pex, DataStream *ds, ProtoStack *ps, Expr *rex)
{
struct udphdr *uh;
struct ipframe *ipf;
Protocol *pr;
uh = (struct udphdr *) ds_inline(ds, sizeof *uh, IP_HDRGRAIN);
if (uh == 0)
return 0;
ipf = PS_TOP(ps, struct ipframe);
ipf->ipf_proto = &udp_proto;
ipf->ipf_sport = ntohs(uh->uh_sport);
ipf->ipf_dport = ntohs(uh->uh_dport);
if ((pr = udp_findproto(ipf->ipf_sport, ipf->ipf_src)) == 0
&& (pr = udp_findproto(ipf->ipf_dport, ipf->ipf_rdst)) == 0
|| pr != pex->ex_prsym->sym_proto) {
return 0;
}
return ex_match(pex, ds, ps, rex);
}
/* ARGSUSED */
static int
udp_fetch(ProtoField *pf, DataStream *ds, ProtoStack *ps, Expr *rex)
{
struct udphdr *uh;
uh = (struct udphdr *) ds_inline(ds, sizeof *uh, IP_HDRGRAIN);
if (uh) {
switch (UDPFID(pf)) {
case SPORT:
rex->ex_val = ntohs(uh->uh_sport);
break;
case DPORT:
rex->ex_val = ntohs(uh->uh_dport);
break;
case LEN:
rex->ex_val = ntohs((u_short) uh->uh_ulen);
break;
case SUM:
rex->ex_val = ntohs(uh->uh_sum);
break;
}
rex->ex_op = EXOP_NUMBER;
return 1;
}
return ds_field(ds, pf, sizeof *uh, rex);
}
static void
udp_decode(DataStream *ds, ProtoStack *ps, PacketView *pv)
{
struct ipframe *ipf;
struct udphdr *uh, hdr;
u_short sum;
Protocol *spr, *dpr;
ipf = PS_TOP(ps, struct ipframe);
uh = (struct udphdr *) ds_inline(ds, sizeof *uh, IP_HDRGRAIN);
if (uh == 0) {
sum = 0;
uh = &hdr;
ds_udphdr(ds, uh);
} else {
u_short len, udpsum;
len = ntohs((u_short) uh->uh_ulen);
udpsum = uh->uh_sum;
uh->uh_sum = 0;
if (udpsum == 0
|| !ip_checksum_pseudohdr(ipf, (char *) uh,
sizeof *uh + ds->ds_count,
&sum)) {
sum = 0;
} else if (sum == 0) {
sum = ~sum;
}
uh->uh_sum = ntohs(udpsum);
uh->uh_sport = ntohs(uh->uh_sport);
uh->uh_dport = ntohs(uh->uh_dport);
uh->uh_ulen = len;
}
spr = udp_findproto(uh->uh_sport, ipf->ipf_src);
dpr = udp_findproto(uh->uh_dport, ipf->ipf_rdst);
pv_showfield(pv, &UDPFIELD(SPORT), &uh->uh_sport,
"%-22.22s", ip_service(uh->uh_sport, udpname, spr));
pv_showfield(pv, &UDPFIELD(DPORT), &uh->uh_dport,
"%-22.22s", ip_service(uh->uh_dport, udpname, dpr));
pv_showfield(pv, &UDPFIELD(LEN), &uh->uh_ulen,
"%-5u", (u_short) uh->uh_ulen);
if (sum != 0 && uh->uh_sum != sum) {
pv_showfield(pv, &UDPFIELD(SUM), &uh->uh_sum,
"%#x [%#x]", uh->uh_sum, sum);
} else {
pv_showfield(pv, &UDPFIELD(SUM), &uh->uh_sum,
"%#-6x", uh->uh_sum);
}
ipf->ipf_proto = &udp_proto;
ipf->ipf_sport = uh->uh_sport;
ipf->ipf_dport = uh->uh_dport;
pv_decodeframe(pv, spr ? spr : dpr, ds, ps);
}