libpcap-1.8.1/0000755000026300017510000000000013003775545011267 5ustar mcrmcrlibpcap-1.8.1/grammar.y0000644000026300017510000005447113003771737013121 0ustar mcrmcr/* * We want a reentrant parser. */ %pure-parser /* * We also want a reentrant scanner, so we have to pass the * handle for the reentrant scanner to the parser, and the * parser has to pass it to the lexical analyzer. * * We use void * rather than yyscan_t because, at least with some * versions of Flex and Bison, if you use yyscan_t in %parse-param and * %lex-param, you have to include scanner.h before grammar.h to get * yyscan_t declared, and you have to include grammar.h before scanner.h * to get YYSTYPE declared. Using void * breaks the cycle; the Flex * documentation says yyscan_t is just a void *. */ %parse-param {void *yyscanner} %lex-param {void *yyscanner} /* * And we need to pass the compiler state to the scanner. */ %parse-param {compiler_state_t *cstate} %{ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 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. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef _WIN32 #include #else /* _WIN32 */ #include #include #endif /* _WIN32 */ #include #ifndef _WIN32 #if __STDC__ struct mbuf; struct rtentry; #endif #include #include #endif /* _WIN32 */ #include #include "pcap-int.h" #include "gencode.h" #include "grammar.h" #include "scanner.h" #ifdef HAVE_NET_PFVAR_H #include #include #include #endif #include "llc.h" #include "ieee80211.h" #include #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #define QSET(q, p, d, a) (q).proto = (p),\ (q).dir = (d),\ (q).addr = (a) struct tok { int v; /* value */ const char *s; /* string */ }; static const struct tok ieee80211_types[] = { { IEEE80211_FC0_TYPE_DATA, "data" }, { IEEE80211_FC0_TYPE_MGT, "mgt" }, { IEEE80211_FC0_TYPE_MGT, "management" }, { IEEE80211_FC0_TYPE_CTL, "ctl" }, { IEEE80211_FC0_TYPE_CTL, "control" }, { 0, NULL } }; static const struct tok ieee80211_mgt_subtypes[] = { { IEEE80211_FC0_SUBTYPE_ASSOC_REQ, "assocreq" }, { IEEE80211_FC0_SUBTYPE_ASSOC_REQ, "assoc-req" }, { IEEE80211_FC0_SUBTYPE_ASSOC_RESP, "assocresp" }, { IEEE80211_FC0_SUBTYPE_ASSOC_RESP, "assoc-resp" }, { IEEE80211_FC0_SUBTYPE_REASSOC_REQ, "reassocreq" }, { IEEE80211_FC0_SUBTYPE_REASSOC_REQ, "reassoc-req" }, { IEEE80211_FC0_SUBTYPE_REASSOC_RESP, "reassocresp" }, { IEEE80211_FC0_SUBTYPE_REASSOC_RESP, "reassoc-resp" }, { IEEE80211_FC0_SUBTYPE_PROBE_REQ, "probereq" }, { IEEE80211_FC0_SUBTYPE_PROBE_REQ, "probe-req" }, { IEEE80211_FC0_SUBTYPE_PROBE_RESP, "proberesp" }, { IEEE80211_FC0_SUBTYPE_PROBE_RESP, "probe-resp" }, { IEEE80211_FC0_SUBTYPE_BEACON, "beacon" }, { IEEE80211_FC0_SUBTYPE_ATIM, "atim" }, { IEEE80211_FC0_SUBTYPE_DISASSOC, "disassoc" }, { IEEE80211_FC0_SUBTYPE_DISASSOC, "disassociation" }, { IEEE80211_FC0_SUBTYPE_AUTH, "auth" }, { IEEE80211_FC0_SUBTYPE_AUTH, "authentication" }, { IEEE80211_FC0_SUBTYPE_DEAUTH, "deauth" }, { IEEE80211_FC0_SUBTYPE_DEAUTH, "deauthentication" }, { 0, NULL } }; static const struct tok ieee80211_ctl_subtypes[] = { { IEEE80211_FC0_SUBTYPE_PS_POLL, "ps-poll" }, { IEEE80211_FC0_SUBTYPE_RTS, "rts" }, { IEEE80211_FC0_SUBTYPE_CTS, "cts" }, { IEEE80211_FC0_SUBTYPE_ACK, "ack" }, { IEEE80211_FC0_SUBTYPE_CF_END, "cf-end" }, { IEEE80211_FC0_SUBTYPE_CF_END_ACK, "cf-end-ack" }, { 0, NULL } }; static const struct tok ieee80211_data_subtypes[] = { { IEEE80211_FC0_SUBTYPE_DATA, "data" }, { IEEE80211_FC0_SUBTYPE_CF_ACK, "data-cf-ack" }, { IEEE80211_FC0_SUBTYPE_CF_POLL, "data-cf-poll" }, { IEEE80211_FC0_SUBTYPE_CF_ACPL, "data-cf-ack-poll" }, { IEEE80211_FC0_SUBTYPE_NODATA, "null" }, { IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK, "cf-ack" }, { IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL, "cf-poll" }, { IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL, "cf-ack-poll" }, { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_DATA, "qos-data" }, { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_ACK, "qos-data-cf-ack" }, { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_POLL, "qos-data-cf-poll" }, { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_ACPL, "qos-data-cf-ack-poll" }, { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA, "qos" }, { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL, "qos-cf-poll" }, { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL, "qos-cf-ack-poll" }, { 0, NULL } }; static const struct tok llc_s_subtypes[] = { { LLC_RR, "rr" }, { LLC_RNR, "rnr" }, { LLC_REJ, "rej" }, { 0, NULL } }; static const struct tok llc_u_subtypes[] = { { LLC_UI, "ui" }, { LLC_UA, "ua" }, { LLC_DISC, "disc" }, { LLC_DM, "dm" }, { LLC_SABME, "sabme" }, { LLC_TEST, "test" }, { LLC_XID, "xid" }, { LLC_FRMR, "frmr" }, { 0, NULL } }; struct type2tok { int type; const struct tok *tok; }; static const struct type2tok ieee80211_type_subtypes[] = { { IEEE80211_FC0_TYPE_MGT, ieee80211_mgt_subtypes }, { IEEE80211_FC0_TYPE_CTL, ieee80211_ctl_subtypes }, { IEEE80211_FC0_TYPE_DATA, ieee80211_data_subtypes }, { 0, NULL } }; static int str2tok(const char *str, const struct tok *toks) { int i; for (i = 0; toks[i].s != NULL; i++) { if (pcap_strcasecmp(toks[i].s, str) == 0) return (toks[i].v); } return (-1); } static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF }; static void yyerror(void *yyscanner, compiler_state_t *cstate, const char *msg) { bpf_syntax_error(cstate, msg); /* NOTREACHED */ } #ifdef HAVE_NET_PFVAR_H static int pfreason_to_num(compiler_state_t *cstate, const char *reason) { const char *reasons[] = PFRES_NAMES; int i; for (i = 0; reasons[i]; i++) { if (pcap_strcasecmp(reason, reasons[i]) == 0) return (i); } bpf_error(cstate, "unknown PF reason"); /*NOTREACHED*/ } static int pfaction_to_num(compiler_state_t *cstate, const char *action) { if (pcap_strcasecmp(action, "pass") == 0 || pcap_strcasecmp(action, "accept") == 0) return (PF_PASS); else if (pcap_strcasecmp(action, "drop") == 0 || pcap_strcasecmp(action, "block") == 0) return (PF_DROP); #if HAVE_PF_NAT_THROUGH_PF_NORDR else if (pcap_strcasecmp(action, "rdr") == 0) return (PF_RDR); else if (pcap_strcasecmp(action, "nat") == 0) return (PF_NAT); else if (pcap_strcasecmp(action, "binat") == 0) return (PF_BINAT); else if (pcap_strcasecmp(action, "nordr") == 0) return (PF_NORDR); #endif else { bpf_error(cstate, "unknown PF action"); /*NOTREACHED*/ } } #else /* !HAVE_NET_PFVAR_H */ static int pfreason_to_num(compiler_state_t *cstate, const char *reason) { bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /*NOTREACHED*/ /* this is to make the VC compiler happy */ return -1; } static int pfaction_to_num(compiler_state_t *cstate, const char *action) { bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /*NOTREACHED*/ /* this is to make the VC compiler happy */ return -1; } #endif /* HAVE_NET_PFVAR_H */ %} %union { int i; bpf_u_int32 h; u_char *e; char *s; struct stmt *stmt; struct arth *a; struct { struct qual q; int atmfieldtype; int mtp3fieldtype; struct block *b; } blk; struct block *rblk; } %type expr id nid pid term rterm qid %type head %type pqual dqual aqual ndaqual %type arth narth %type byteop pname pnum relop irelop %type and or paren not null prog %type other pfvar p80211 pllc %type atmtype atmmultitype %type atmfield %type atmfieldvalue atmvalue atmlistvalue %type mtp2type %type mtp3field %type mtp3fieldvalue mtp3value mtp3listvalue %token DST SRC HOST GATEWAY %token NET NETMASK PORT PORTRANGE LESS GREATER PROTO PROTOCHAIN CBYTE %token ARP RARP IP SCTP TCP UDP ICMP IGMP IGRP PIM VRRP CARP %token ATALK AARP DECNET LAT SCA MOPRC MOPDL %token TK_BROADCAST TK_MULTICAST %token NUM INBOUND OUTBOUND %token PF_IFNAME PF_RSET PF_RNR PF_SRNR PF_REASON PF_ACTION %token TYPE SUBTYPE DIR ADDR1 ADDR2 ADDR3 ADDR4 RA TA %token LINK %token GEQ LEQ NEQ %token ID EID HID HID6 AID %token LSH RSH %token LEN %token IPV6 ICMPV6 AH ESP %token VLAN MPLS %token PPPOED PPPOES GENEVE %token ISO ESIS CLNP ISIS L1 L2 IIH LSP SNP CSNP PSNP %token STP %token IPX %token NETBEUI %token LANE LLC METAC BCC SC ILMIC OAMF4EC OAMF4SC %token OAM OAMF4 CONNECTMSG METACONNECT %token VPI VCI %token RADIO %token FISU LSSU MSU HFISU HLSSU HMSU %token SIO OPC DPC SLS HSIO HOPC HDPC HSLS %type ID %type EID %type AID %type HID HID6 %type NUM action reason type subtype type_subtype dir %left OR AND %nonassoc '!' %left '|' %left '&' %left LSH RSH %left '+' '-' %left '*' '/' %nonassoc UMINUS %% prog: null expr { finish_parse(cstate, $2.b); } | null ; null: /* null */ { $$.q = qerr; } ; expr: term | expr and term { gen_and($1.b, $3.b); $$ = $3; } | expr and id { gen_and($1.b, $3.b); $$ = $3; } | expr or term { gen_or($1.b, $3.b); $$ = $3; } | expr or id { gen_or($1.b, $3.b); $$ = $3; } ; and: AND { $$ = $0; } ; or: OR { $$ = $0; } ; id: nid | pnum { $$.b = gen_ncode(cstate, NULL, (bpf_u_int32)$1, $$.q = $0.q); } | paren pid ')' { $$ = $2; } ; nid: ID { $$.b = gen_scode(cstate, $1, $$.q = $0.q); } | HID '/' NUM { $$.b = gen_mcode(cstate, $1, NULL, $3, $$.q = $0.q); } | HID NETMASK HID { $$.b = gen_mcode(cstate, $1, $3, 0, $$.q = $0.q); } | HID { /* Decide how to parse HID based on proto */ $$.q = $0.q; if ($$.q.addr == Q_PORT) bpf_error(cstate, "'port' modifier applied to ip host"); else if ($$.q.addr == Q_PORTRANGE) bpf_error(cstate, "'portrange' modifier applied to ip host"); else if ($$.q.addr == Q_PROTO) bpf_error(cstate, "'proto' modifier applied to ip host"); else if ($$.q.addr == Q_PROTOCHAIN) bpf_error(cstate, "'protochain' modifier applied to ip host"); $$.b = gen_ncode(cstate, $1, 0, $$.q); } | HID6 '/' NUM { #ifdef INET6 $$.b = gen_mcode6(cstate, $1, NULL, $3, $$.q = $0.q); #else bpf_error(cstate, "'ip6addr/prefixlen' not supported " "in this configuration"); #endif /*INET6*/ } | HID6 { #ifdef INET6 $$.b = gen_mcode6(cstate, $1, 0, 128, $$.q = $0.q); #else bpf_error(cstate, "'ip6addr' not supported " "in this configuration"); #endif /*INET6*/ } | EID { $$.b = gen_ecode(cstate, $1, $$.q = $0.q); /* * $1 was allocated by "pcap_ether_aton()", * so we must free it now that we're done * with it. */ free($1); } | AID { $$.b = gen_acode(cstate, $1, $$.q = $0.q); /* * $1 was allocated by "pcap_ether_aton()", * so we must free it now that we're done * with it. */ free($1); } | not id { gen_not($2.b); $$ = $2; } ; not: '!' { $$ = $0; } ; paren: '(' { $$ = $0; } ; pid: nid | qid and id { gen_and($1.b, $3.b); $$ = $3; } | qid or id { gen_or($1.b, $3.b); $$ = $3; } ; qid: pnum { $$.b = gen_ncode(cstate, NULL, (bpf_u_int32)$1, $$.q = $0.q); } | pid ; term: rterm | not term { gen_not($2.b); $$ = $2; } ; head: pqual dqual aqual { QSET($$.q, $1, $2, $3); } | pqual dqual { QSET($$.q, $1, $2, Q_DEFAULT); } | pqual aqual { QSET($$.q, $1, Q_DEFAULT, $2); } | pqual PROTO { QSET($$.q, $1, Q_DEFAULT, Q_PROTO); } | pqual PROTOCHAIN { QSET($$.q, $1, Q_DEFAULT, Q_PROTOCHAIN); } | pqual ndaqual { QSET($$.q, $1, Q_DEFAULT, $2); } ; rterm: head id { $$ = $2; } | paren expr ')' { $$.b = $2.b; $$.q = $1.q; } | pname { $$.b = gen_proto_abbrev(cstate, $1); $$.q = qerr; } | arth relop arth { $$.b = gen_relation(cstate, $2, $1, $3, 0); $$.q = qerr; } | arth irelop arth { $$.b = gen_relation(cstate, $2, $1, $3, 1); $$.q = qerr; } | other { $$.b = $1; $$.q = qerr; } | atmtype { $$.b = gen_atmtype_abbrev(cstate, $1); $$.q = qerr; } | atmmultitype { $$.b = gen_atmmulti_abbrev(cstate, $1); $$.q = qerr; } | atmfield atmvalue { $$.b = $2.b; $$.q = qerr; } | mtp2type { $$.b = gen_mtp2type_abbrev(cstate, $1); $$.q = qerr; } | mtp3field mtp3value { $$.b = $2.b; $$.q = qerr; } ; /* protocol level qualifiers */ pqual: pname | { $$ = Q_DEFAULT; } ; /* 'direction' qualifiers */ dqual: SRC { $$ = Q_SRC; } | DST { $$ = Q_DST; } | SRC OR DST { $$ = Q_OR; } | DST OR SRC { $$ = Q_OR; } | SRC AND DST { $$ = Q_AND; } | DST AND SRC { $$ = Q_AND; } | ADDR1 { $$ = Q_ADDR1; } | ADDR2 { $$ = Q_ADDR2; } | ADDR3 { $$ = Q_ADDR3; } | ADDR4 { $$ = Q_ADDR4; } | RA { $$ = Q_RA; } | TA { $$ = Q_TA; } ; /* address type qualifiers */ aqual: HOST { $$ = Q_HOST; } | NET { $$ = Q_NET; } | PORT { $$ = Q_PORT; } | PORTRANGE { $$ = Q_PORTRANGE; } ; /* non-directional address type qualifiers */ ndaqual: GATEWAY { $$ = Q_GATEWAY; } ; pname: LINK { $$ = Q_LINK; } | IP { $$ = Q_IP; } | ARP { $$ = Q_ARP; } | RARP { $$ = Q_RARP; } | SCTP { $$ = Q_SCTP; } | TCP { $$ = Q_TCP; } | UDP { $$ = Q_UDP; } | ICMP { $$ = Q_ICMP; } | IGMP { $$ = Q_IGMP; } | IGRP { $$ = Q_IGRP; } | PIM { $$ = Q_PIM; } | VRRP { $$ = Q_VRRP; } | CARP { $$ = Q_CARP; } | ATALK { $$ = Q_ATALK; } | AARP { $$ = Q_AARP; } | DECNET { $$ = Q_DECNET; } | LAT { $$ = Q_LAT; } | SCA { $$ = Q_SCA; } | MOPDL { $$ = Q_MOPDL; } | MOPRC { $$ = Q_MOPRC; } | IPV6 { $$ = Q_IPV6; } | ICMPV6 { $$ = Q_ICMPV6; } | AH { $$ = Q_AH; } | ESP { $$ = Q_ESP; } | ISO { $$ = Q_ISO; } | ESIS { $$ = Q_ESIS; } | ISIS { $$ = Q_ISIS; } | L1 { $$ = Q_ISIS_L1; } | L2 { $$ = Q_ISIS_L2; } | IIH { $$ = Q_ISIS_IIH; } | LSP { $$ = Q_ISIS_LSP; } | SNP { $$ = Q_ISIS_SNP; } | PSNP { $$ = Q_ISIS_PSNP; } | CSNP { $$ = Q_ISIS_CSNP; } | CLNP { $$ = Q_CLNP; } | STP { $$ = Q_STP; } | IPX { $$ = Q_IPX; } | NETBEUI { $$ = Q_NETBEUI; } | RADIO { $$ = Q_RADIO; } ; other: pqual TK_BROADCAST { $$ = gen_broadcast(cstate, $1); } | pqual TK_MULTICAST { $$ = gen_multicast(cstate, $1); } | LESS NUM { $$ = gen_less(cstate, $2); } | GREATER NUM { $$ = gen_greater(cstate, $2); } | CBYTE NUM byteop NUM { $$ = gen_byteop(cstate, $3, $2, $4); } | INBOUND { $$ = gen_inbound(cstate, 0); } | OUTBOUND { $$ = gen_inbound(cstate, 1); } | VLAN pnum { $$ = gen_vlan(cstate, $2); } | VLAN { $$ = gen_vlan(cstate, -1); } | MPLS pnum { $$ = gen_mpls(cstate, $2); } | MPLS { $$ = gen_mpls(cstate, -1); } | PPPOED { $$ = gen_pppoed(cstate); } | PPPOES pnum { $$ = gen_pppoes(cstate, $2); } | PPPOES { $$ = gen_pppoes(cstate, -1); } | GENEVE pnum { $$ = gen_geneve(cstate, $2); } | GENEVE { $$ = gen_geneve(cstate, -1); } | pfvar { $$ = $1; } | pqual p80211 { $$ = $2; } | pllc { $$ = $1; } ; pfvar: PF_IFNAME ID { $$ = gen_pf_ifname(cstate, $2); } | PF_RSET ID { $$ = gen_pf_ruleset(cstate, $2); } | PF_RNR NUM { $$ = gen_pf_rnr(cstate, $2); } | PF_SRNR NUM { $$ = gen_pf_srnr(cstate, $2); } | PF_REASON reason { $$ = gen_pf_reason(cstate, $2); } | PF_ACTION action { $$ = gen_pf_action(cstate, $2); } ; p80211: TYPE type SUBTYPE subtype { $$ = gen_p80211_type(cstate, $2 | $4, IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK); } | TYPE type { $$ = gen_p80211_type(cstate, $2, IEEE80211_FC0_TYPE_MASK); } | SUBTYPE type_subtype { $$ = gen_p80211_type(cstate, $2, IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK); } | DIR dir { $$ = gen_p80211_fcdir(cstate, $2); } ; type: NUM | ID { $$ = str2tok($1, ieee80211_types); if ($$ == -1) bpf_error(cstate, "unknown 802.11 type name"); } ; subtype: NUM | ID { const struct tok *types = NULL; int i; for (i = 0;; i++) { if (ieee80211_type_subtypes[i].tok == NULL) { /* Ran out of types */ bpf_error(cstate, "unknown 802.11 type"); break; } if ($-1 == ieee80211_type_subtypes[i].type) { types = ieee80211_type_subtypes[i].tok; break; } } $$ = str2tok($1, types); if ($$ == -1) bpf_error(cstate, "unknown 802.11 subtype name"); } ; type_subtype: ID { int i; for (i = 0;; i++) { if (ieee80211_type_subtypes[i].tok == NULL) { /* Ran out of types */ bpf_error(cstate, "unknown 802.11 type name"); break; } $$ = str2tok($1, ieee80211_type_subtypes[i].tok); if ($$ != -1) { $$ |= ieee80211_type_subtypes[i].type; break; } } } ; pllc: LLC { $$ = gen_llc(cstate); } | LLC ID { if (pcap_strcasecmp($2, "i") == 0) $$ = gen_llc_i(cstate); else if (pcap_strcasecmp($2, "s") == 0) $$ = gen_llc_s(cstate); else if (pcap_strcasecmp($2, "u") == 0) $$ = gen_llc_u(cstate); else { int subtype; subtype = str2tok($2, llc_s_subtypes); if (subtype != -1) $$ = gen_llc_s_subtype(cstate, subtype); else { subtype = str2tok($2, llc_u_subtypes); if (subtype == -1) bpf_error(cstate, "unknown LLC type name \"%s\"", $2); $$ = gen_llc_u_subtype(cstate, subtype); } } } /* sigh, "rnr" is already a keyword for PF */ | LLC PF_RNR { $$ = gen_llc_s_subtype(cstate, LLC_RNR); } ; dir: NUM | ID { if (pcap_strcasecmp($1, "nods") == 0) $$ = IEEE80211_FC1_DIR_NODS; else if (pcap_strcasecmp($1, "tods") == 0) $$ = IEEE80211_FC1_DIR_TODS; else if (pcap_strcasecmp($1, "fromds") == 0) $$ = IEEE80211_FC1_DIR_FROMDS; else if (pcap_strcasecmp($1, "dstods") == 0) $$ = IEEE80211_FC1_DIR_DSTODS; else bpf_error(cstate, "unknown 802.11 direction"); } ; reason: NUM { $$ = $1; } | ID { $$ = pfreason_to_num(cstate, $1); } ; action: ID { $$ = pfaction_to_num(cstate, $1); } ; relop: '>' { $$ = BPF_JGT; } | GEQ { $$ = BPF_JGE; } | '=' { $$ = BPF_JEQ; } ; irelop: LEQ { $$ = BPF_JGT; } | '<' { $$ = BPF_JGE; } | NEQ { $$ = BPF_JEQ; } ; arth: pnum { $$ = gen_loadi(cstate, $1); } | narth ; narth: pname '[' arth ']' { $$ = gen_load(cstate, $1, $3, 1); } | pname '[' arth ':' NUM ']' { $$ = gen_load(cstate, $1, $3, $5); } | arth '+' arth { $$ = gen_arth(cstate, BPF_ADD, $1, $3); } | arth '-' arth { $$ = gen_arth(cstate, BPF_SUB, $1, $3); } | arth '*' arth { $$ = gen_arth(cstate, BPF_MUL, $1, $3); } | arth '/' arth { $$ = gen_arth(cstate, BPF_DIV, $1, $3); } | arth '%' arth { $$ = gen_arth(cstate, BPF_MOD, $1, $3); } | arth '&' arth { $$ = gen_arth(cstate, BPF_AND, $1, $3); } | arth '|' arth { $$ = gen_arth(cstate, BPF_OR, $1, $3); } | arth '^' arth { $$ = gen_arth(cstate, BPF_XOR, $1, $3); } | arth LSH arth { $$ = gen_arth(cstate, BPF_LSH, $1, $3); } | arth RSH arth { $$ = gen_arth(cstate, BPF_RSH, $1, $3); } | '-' arth %prec UMINUS { $$ = gen_neg(cstate, $2); } | paren narth ')' { $$ = $2; } | LEN { $$ = gen_loadlen(cstate); } ; byteop: '&' { $$ = '&'; } | '|' { $$ = '|'; } | '<' { $$ = '<'; } | '>' { $$ = '>'; } | '=' { $$ = '='; } ; pnum: NUM | paren pnum ')' { $$ = $2; } ; atmtype: LANE { $$ = A_LANE; } | METAC { $$ = A_METAC; } | BCC { $$ = A_BCC; } | OAMF4EC { $$ = A_OAMF4EC; } | OAMF4SC { $$ = A_OAMF4SC; } | SC { $$ = A_SC; } | ILMIC { $$ = A_ILMIC; } ; atmmultitype: OAM { $$ = A_OAM; } | OAMF4 { $$ = A_OAMF4; } | CONNECTMSG { $$ = A_CONNECTMSG; } | METACONNECT { $$ = A_METACONNECT; } ; /* ATM field types quantifier */ atmfield: VPI { $$.atmfieldtype = A_VPI; } | VCI { $$.atmfieldtype = A_VCI; } ; atmvalue: atmfieldvalue | relop NUM { $$.b = gen_atmfield_code(cstate, $0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 0); } | irelop NUM { $$.b = gen_atmfield_code(cstate, $0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 1); } | paren atmlistvalue ')' { $$.b = $2.b; $$.q = qerr; } ; atmfieldvalue: NUM { $$.atmfieldtype = $0.atmfieldtype; if ($$.atmfieldtype == A_VPI || $$.atmfieldtype == A_VCI) $$.b = gen_atmfield_code(cstate, $$.atmfieldtype, (bpf_int32) $1, BPF_JEQ, 0); } ; atmlistvalue: atmfieldvalue | atmlistvalue or atmfieldvalue { gen_or($1.b, $3.b); $$ = $3; } ; /* MTP2 types quantifier */ mtp2type: FISU { $$ = M_FISU; } | LSSU { $$ = M_LSSU; } | MSU { $$ = M_MSU; } | HFISU { $$ = MH_FISU; } | HLSSU { $$ = MH_LSSU; } | HMSU { $$ = MH_MSU; } ; /* MTP3 field types quantifier */ mtp3field: SIO { $$.mtp3fieldtype = M_SIO; } | OPC { $$.mtp3fieldtype = M_OPC; } | DPC { $$.mtp3fieldtype = M_DPC; } | SLS { $$.mtp3fieldtype = M_SLS; } | HSIO { $$.mtp3fieldtype = MH_SIO; } | HOPC { $$.mtp3fieldtype = MH_OPC; } | HDPC { $$.mtp3fieldtype = MH_DPC; } | HSLS { $$.mtp3fieldtype = MH_SLS; } ; mtp3value: mtp3fieldvalue | relop NUM { $$.b = gen_mtp3field_code(cstate, $0.mtp3fieldtype, (u_int)$2, (u_int)$1, 0); } | irelop NUM { $$.b = gen_mtp3field_code(cstate, $0.mtp3fieldtype, (u_int)$2, (u_int)$1, 1); } | paren mtp3listvalue ')' { $$.b = $2.b; $$.q = qerr; } ; mtp3fieldvalue: NUM { $$.mtp3fieldtype = $0.mtp3fieldtype; if ($$.mtp3fieldtype == M_SIO || $$.mtp3fieldtype == M_OPC || $$.mtp3fieldtype == M_DPC || $$.mtp3fieldtype == M_SLS || $$.mtp3fieldtype == MH_SIO || $$.mtp3fieldtype == MH_OPC || $$.mtp3fieldtype == MH_DPC || $$.mtp3fieldtype == MH_SLS) $$.b = gen_mtp3field_code(cstate, $$.mtp3fieldtype, (u_int) $1, BPF_JEQ, 0); } ; mtp3listvalue: mtp3fieldvalue | mtp3listvalue or mtp3fieldvalue { gen_or($1.b, $3.b); $$ = $3; } ; %% libpcap-1.8.1/pcap_setnonblock.3pcap0000644000026300017510000000546013003771737015547 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_SETNONBLOCK 3PCAP "18 October 2014" .SH NAME pcap_setnonblock, pcap_getnonblock \- set or get the state of non-blocking mode on a capture device .SH SYNOPSIS .nf .ft B #include .ft .LP .nf .ft B char errbuf[PCAP_ERRBUF_SIZE]; .ft .LP .ft B int pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf); int pcap_getnonblock(pcap_t *p, char *errbuf); .ft .fi .SH DESCRIPTION .B pcap_setnonblock() puts a capture handle into ``non-blocking'' mode, or takes it out of ``non-blocking'' mode, depending on whether the .I nonblock argument is non-zero or zero. It has no effect on ``savefiles''. If there is an error, \-1 is returned and .I errbuf is filled in with an appropriate error message; otherwise, 0 is returned. In ``non-blocking'' mode, an attempt to read from the capture descriptor with .B pcap_dispatch() will, if no packets are currently available to be read, return 0 immediately rather than blocking waiting for packets to arrive. .B pcap_loop() and .B pcap_next() will not work in ``non-blocking'' mode. .PP When first activated with .B pcap_activate() or opened with .B pcap_open_live() , a capture handle is not in ``non-blocking mode''; a call to .B pcap_setnonblock() is required in order to put it into ``non-blocking'' mode. .SH RETURN VALUE .B pcap_getnonblock() returns the current ``non-blocking'' state of the capture descriptor; it always returns 0 on ``savefiles''. If there is an error, \-1 is returned and .I errbuf is filled in with an appropriate error message. .PP .I errbuf is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. .SH SEE ALSO pcap(3PCAP), pcap_loop(3PCAP), pcap_next_ex(3PCAP), pcap_geterr(3PCAP) libpcap-1.8.1/fad-glifc.c0000644000026300017510000002327513003771737013257 0ustar mcrmcr/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ /* * Copyright (c) 1994, 1995, 1996, 1997, 1998 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #ifdef HAVE_SYS_SOCKIO_H #include #endif #include /* concession to AIX */ struct mbuf; /* Squelch compiler warnings on some platforms for */ struct rtentry; /* declarations in */ #include #include #include #include #include #include #include #include #include #include "pcap-int.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif /* * Get a list of all interfaces that are up and that we can open. * Returns -1 on error, 0 otherwise. * The list, as returned through "alldevsp", may be null if no interfaces * were up and could be opened. * * This is the implementation used on platforms that have SIOCGLIFCONF * but don't have "getifaddrs()". (Solaris 8 and later; we use * SIOCGLIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.) */ int pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf, int (*check_usable)(const char *)) { pcap_if_t *devlist = NULL; register int fd4, fd6, fd; register struct lifreq *ifrp, *ifend; struct lifnum ifn; struct lifconf ifc; char *buf = NULL; unsigned buf_size; #ifdef HAVE_SOLARIS char *p, *q; #endif struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr; struct sockaddr *netmask, *broadaddr, *dstaddr; int ret = 0; /* * Create a socket from which to fetch the list of interfaces, * and from which to fetch IPv4 information. */ fd4 = socket(AF_INET, SOCK_DGRAM, 0); if (fd4 < 0) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); return (-1); } /* * Create a socket from which to fetch IPv6 information. */ fd6 = socket(AF_INET6, SOCK_DGRAM, 0); if (fd6 < 0) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); (void)close(fd4); return (-1); } /* * How many entries will SIOCGLIFCONF return? */ ifn.lifn_family = AF_UNSPEC; ifn.lifn_flags = 0; ifn.lifn_count = 0; if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGLIFNUM: %s", pcap_strerror(errno)); (void)close(fd6); (void)close(fd4); return (-1); } /* * Allocate a buffer for those entries. */ buf_size = ifn.lifn_count * sizeof (struct lifreq); buf = malloc(buf_size); if (buf == NULL) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); (void)close(fd6); (void)close(fd4); return (-1); } /* * Get the entries. */ ifc.lifc_len = buf_size; ifc.lifc_buf = buf; ifc.lifc_family = AF_UNSPEC; ifc.lifc_flags = 0; memset(buf, 0, buf_size); if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGLIFCONF: %s", pcap_strerror(errno)); (void)close(fd6); (void)close(fd4); free(buf); return (-1); } /* * Loop over the entries. */ ifrp = (struct lifreq *)buf; ifend = (struct lifreq *)(buf + ifc.lifc_len); for (; ifrp < ifend; ifrp++) { /* * Skip entries that begin with "dummy". * XXX - what are these? Is this Linux-specific? * Are there platforms on which we shouldn't do this? */ if (strncmp(ifrp->lifr_name, "dummy", 5) == 0) continue; /* * Can we capture on this device? */ if (!(*check_usable)(ifrp->lifr_name)) { /* * No. */ continue; } /* * IPv6 or not? */ if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6) fd = fd6; else fd = fd4; /* * Get the flags for this interface. */ strncpy(ifrflags.lifr_name, ifrp->lifr_name, sizeof(ifrflags.lifr_name)); if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) { if (errno == ENXIO) continue; (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGLIFFLAGS: %.*s: %s", (int)sizeof(ifrflags.lifr_name), ifrflags.lifr_name, pcap_strerror(errno)); ret = -1; break; } /* * Get the netmask for this address on this interface. */ strncpy(ifrnetmask.lifr_name, ifrp->lifr_name, sizeof(ifrnetmask.lifr_name)); memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr, sizeof(ifrnetmask.lifr_addr)); if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) { if (errno == EADDRNOTAVAIL) { /* * Not available. */ netmask = NULL; } else { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGLIFNETMASK: %.*s: %s", (int)sizeof(ifrnetmask.lifr_name), ifrnetmask.lifr_name, pcap_strerror(errno)); ret = -1; break; } } else netmask = (struct sockaddr *)&ifrnetmask.lifr_addr; /* * Get the broadcast address for this address on this * interface (if any). */ if (ifrflags.lifr_flags & IFF_BROADCAST) { strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name, sizeof(ifrbroadaddr.lifr_name)); memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr, sizeof(ifrbroadaddr.lifr_addr)); if (ioctl(fd, SIOCGLIFBRDADDR, (char *)&ifrbroadaddr) < 0) { if (errno == EADDRNOTAVAIL) { /* * Not available. */ broadaddr = NULL; } else { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGLIFBRDADDR: %.*s: %s", (int)sizeof(ifrbroadaddr.lifr_name), ifrbroadaddr.lifr_name, pcap_strerror(errno)); ret = -1; break; } } else broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr; } else { /* * Not a broadcast interface, so no broadcast * address. */ broadaddr = NULL; } /* * Get the destination address for this address on this * interface (if any). */ if (ifrflags.lifr_flags & IFF_POINTOPOINT) { strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name, sizeof(ifrdstaddr.lifr_name)); memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr, sizeof(ifrdstaddr.lifr_addr)); if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&ifrdstaddr) < 0) { if (errno == EADDRNOTAVAIL) { /* * Not available. */ dstaddr = NULL; } else { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGLIFDSTADDR: %.*s: %s", (int)sizeof(ifrdstaddr.lifr_name), ifrdstaddr.lifr_name, pcap_strerror(errno)); ret = -1; break; } } else dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr; } else dstaddr = NULL; #ifdef HAVE_SOLARIS /* * If this entry has a colon followed by a number at * the end, it's a logical interface. Those are just * the way you assign multiple IP addresses to a real * interface, so an entry for a logical interface should * be treated like the entry for the real interface; * we do that by stripping off the ":" and the number. */ p = strchr(ifrp->lifr_name, ':'); if (p != NULL) { /* * We have a ":"; is it followed by a number? */ q = p + 1; while (isdigit((unsigned char)*q)) q++; if (*q == '\0') { /* * All digits after the ":" until the end. * Strip off the ":" and everything after * it. */ *p = '\0'; } } #endif /* * Add information for this address to the list. */ if (add_addr_to_iflist(&devlist, ifrp->lifr_name, if_flags_to_pcap_flags(ifrp->lifr_name, ifrflags.lifr_flags), (struct sockaddr *)&ifrp->lifr_addr, sizeof (struct sockaddr_storage), netmask, sizeof (struct sockaddr_storage), broadaddr, sizeof (struct sockaddr_storage), dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) { ret = -1; break; } } free(buf); (void)close(fd6); (void)close(fd4); if (ret == -1) { /* * We had an error; free the list we've been constructing. */ if (devlist != NULL) { pcap_freealldevs(devlist); devlist = NULL; } } *alldevsp = devlist; return (ret); } libpcap-1.8.1/llc.h0000644000026300017510000000507613003771737012221 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1997 * 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. */ /* * Definitions for information in the LLC header. */ #define LLC_U_FMT 3 #define LLC_GSAP 1 #define LLC_IG 1 /* Individual / Group */ #define LLC_S_FMT 1 #define LLC_U_POLL 0x10 #define LLC_IS_POLL 0x0100 #define LLC_XID_FI 0x81 #define LLC_U_CMD_MASK 0xef #define LLC_UI 0x03 #define LLC_UA 0x63 #define LLC_DISC 0x43 #define LLC_DM 0x0f #define LLC_SABME 0x6f #define LLC_TEST 0xe3 #define LLC_XID 0xaf #define LLC_FRMR 0x87 #define LLC_S_CMD_MASK 0x0f #define LLC_RR 0x0001 #define LLC_RNR 0x0005 #define LLC_REJ 0x0009 #define LLC_IS_NR(is) (((is) >> 9) & 0x7f) #define LLC_I_NS(is) (((is) >> 1) & 0x7f) /* * 802.2 LLC SAP values. */ #ifndef LLCSAP_NULL #define LLCSAP_NULL 0x00 #endif #ifndef LLCSAP_GLOBAL #define LLCSAP_GLOBAL 0xff #endif #ifndef LLCSAP_8021B_I #define LLCSAP_8021B_I 0x02 #endif #ifndef LLCSAP_8021B_G #define LLCSAP_8021B_G 0x03 #endif #ifndef LLCSAP_IP #define LLCSAP_IP 0x06 #endif #ifndef LLCSAP_PROWAYNM #define LLCSAP_PROWAYNM 0x0e #endif #ifndef LLCSAP_8021D #define LLCSAP_8021D 0x42 #endif #ifndef LLCSAP_RS511 #define LLCSAP_RS511 0x4e #endif #ifndef LLCSAP_ISO8208 #define LLCSAP_ISO8208 0x7e #endif #ifndef LLCSAP_PROWAY #define LLCSAP_PROWAY 0x8e #endif #ifndef LLCSAP_SNAP #define LLCSAP_SNAP 0xaa #endif #ifndef LLCSAP_IPX #define LLCSAP_IPX 0xe0 #endif #ifndef LLCSAP_NETBEUI #define LLCSAP_NETBEUI 0xf0 #endif #ifndef LLCSAP_ISONS #define LLCSAP_ISONS 0xfe #endif libpcap-1.8.1/sunatmpos.h0000644000026300017510000000413013003771737013466 0ustar mcrmcr/* * Copyright (c) 1997 Yen Yen Lim and North Dakota State University * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Yen Yen Lim and North Dakota State University * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* SunATM header for ATM packet */ #define SUNATM_DIR_POS 0 #define SUNATM_VPI_POS 1 #define SUNATM_VCI_POS 2 #define SUNATM_PKT_BEGIN_POS 4 /* Start of ATM packet */ /* Protocol type values in the bottom for bits of the byte at SUNATM_DIR_POS. */ #define PT_LANE 0x01 /* LANE */ #define PT_LLC 0x02 /* LLC encapsulation */ #define PT_ILMI 0x05 /* ILMI */ #define PT_QSAAL 0x06 /* Q.SAAL */ libpcap-1.8.1/sf-pcap-ng.c0000644000026300017510000010732413003771737013374 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. * * sf-pcap-ng.c - pcap-ng-file-format-specific code from savefile.c */ #ifndef lint static const char rcsid[] _U_ = "@(#) $Header$ (LBL)"; #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef _WIN32 #include #else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_BITYPES_H #include #endif #include #endif /* _WIN32 */ #include #include #include #include #include #include "pcap-int.h" #include "pcap-common.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #include "sf-pcap-ng.h" /* * Block types. */ /* * Common part at the beginning of all blocks. */ struct block_header { bpf_u_int32 block_type; bpf_u_int32 total_length; }; /* * Common trailer at the end of all blocks. */ struct block_trailer { bpf_u_int32 total_length; }; /* * Common options. */ #define OPT_ENDOFOPT 0 /* end of options */ #define OPT_COMMENT 1 /* comment string */ /* * Option header. */ struct option_header { u_short option_code; u_short option_length; }; /* * Structures for the part of each block type following the common * part. */ /* * Section Header Block. */ #define BT_SHB 0x0A0D0D0A struct section_header_block { bpf_u_int32 byte_order_magic; u_short major_version; u_short minor_version; u_int64_t section_length; /* followed by options and trailer */ }; /* * Byte-order magic value. */ #define BYTE_ORDER_MAGIC 0x1A2B3C4D /* * Current version number. If major_version isn't PCAP_NG_VERSION_MAJOR, * that means that this code can't read the file. */ #define PCAP_NG_VERSION_MAJOR 1 #define PCAP_NG_VERSION_MINOR 0 /* * Interface Description Block. */ #define BT_IDB 0x00000001 struct interface_description_block { u_short linktype; u_short reserved; bpf_u_int32 snaplen; /* followed by options and trailer */ }; /* * Options in the IDB. */ #define IF_NAME 2 /* interface name string */ #define IF_DESCRIPTION 3 /* interface description string */ #define IF_IPV4ADDR 4 /* interface's IPv4 address and netmask */ #define IF_IPV6ADDR 5 /* interface's IPv6 address and prefix length */ #define IF_MACADDR 6 /* interface's MAC address */ #define IF_EUIADDR 7 /* interface's EUI address */ #define IF_SPEED 8 /* interface's speed, in bits/s */ #define IF_TSRESOL 9 /* interface's time stamp resolution */ #define IF_TZONE 10 /* interface's time zone */ #define IF_FILTER 11 /* filter used when capturing on interface */ #define IF_OS 12 /* string OS on which capture on this interface was done */ #define IF_FCSLEN 13 /* FCS length for this interface */ #define IF_TSOFFSET 14 /* time stamp offset for this interface */ /* * Enhanced Packet Block. */ #define BT_EPB 0x00000006 struct enhanced_packet_block { bpf_u_int32 interface_id; bpf_u_int32 timestamp_high; bpf_u_int32 timestamp_low; bpf_u_int32 caplen; bpf_u_int32 len; /* followed by packet data, options, and trailer */ }; /* * Simple Packet Block. */ #define BT_SPB 0x00000003 struct simple_packet_block { bpf_u_int32 len; /* followed by packet data and trailer */ }; /* * Packet Block. */ #define BT_PB 0x00000002 struct packet_block { u_short interface_id; u_short drops_count; bpf_u_int32 timestamp_high; bpf_u_int32 timestamp_low; bpf_u_int32 caplen; bpf_u_int32 len; /* followed by packet data, options, and trailer */ }; /* * Block cursor - used when processing the contents of a block. * Contains a pointer into the data being processed and a count * of bytes remaining in the block. */ struct block_cursor { u_char *data; size_t data_remaining; bpf_u_int32 block_type; }; typedef enum { PASS_THROUGH, SCALE_UP_DEC, SCALE_DOWN_DEC, SCALE_UP_BIN, SCALE_DOWN_BIN } tstamp_scale_type_t; /* * Per-interface information. */ struct pcap_ng_if { u_int tsresol; /* time stamp resolution */ tstamp_scale_type_t scale_type; /* how to scale */ u_int scale_factor; /* time stamp scale factor for power-of-10 tsresol */ u_int64_t tsoffset; /* time stamp offset */ }; struct pcap_ng_sf { u_int user_tsresol; /* time stamp resolution requested by the user */ bpf_u_int32 ifcount; /* number of interfaces seen in this capture */ bpf_u_int32 ifaces_size; /* size of array below */ struct pcap_ng_if *ifaces; /* array of interface information */ }; static void pcap_ng_cleanup(pcap_t *p); static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data); static int read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof, char *errbuf) { size_t amt_read; amt_read = fread(buf, 1, bytes_to_read, fp); if (amt_read != bytes_to_read) { if (ferror(fp)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { if (amt_read == 0 && !fail_on_eof) return (0); /* EOF */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %lu bytes, only got %lu", (unsigned long)bytes_to_read, (unsigned long)amt_read); } return (-1); } return (1); } static int read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) { int status; struct block_header bhdr; u_char *bdata; size_t data_remaining; status = read_bytes(fp, &bhdr, sizeof(bhdr), 0, errbuf); if (status <= 0) return (status); /* error or EOF */ if (p->swapped) { bhdr.block_type = SWAPLONG(bhdr.block_type); bhdr.total_length = SWAPLONG(bhdr.total_length); } /* * Is this block "too big"? * * We choose 16MB as "too big", for now, so that we handle * "reasonably" large buffers but don't chew up all the * memory if we read a malformed file. */ if (bhdr.total_length > 16*1024*1024) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap-ng block size %u > maximum %u", bhdr.total_length, 16*1024*1024); return (-1); } /* * Is this block "too small" - i.e., is it shorter than a block * header plus a block trailer? */ if (bhdr.total_length < sizeof(struct block_header) + sizeof(struct block_trailer)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "block in pcap-ng dump file has a length of %u < %lu", bhdr.total_length, (unsigned long)(sizeof(struct block_header) + sizeof(struct block_trailer))); return (-1); } /* * Is the buffer big enough? */ if (p->bufsize < bhdr.total_length) { /* * No - make it big enough. */ void *bigger_buffer; bigger_buffer = realloc(p->buffer, bhdr.total_length); if (bigger_buffer == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); return (-1); } p->buffer = bigger_buffer; } /* * Copy the stuff we've read to the buffer, and read the rest * of the block. */ memcpy(p->buffer, &bhdr, sizeof(bhdr)); bdata = (u_char *)p->buffer + sizeof(bhdr); data_remaining = bhdr.total_length - sizeof(bhdr); if (read_bytes(fp, bdata, data_remaining, 1, errbuf) == -1) return (-1); /* * Initialize the cursor. */ cursor->data = bdata; cursor->data_remaining = data_remaining - sizeof(struct block_trailer); cursor->block_type = bhdr.block_type; return (1); } static void * get_from_block_data(struct block_cursor *cursor, size_t chunk_size, char *errbuf) { void *data; /* * Make sure we have the specified amount of data remaining in * the block data. */ if (cursor->data_remaining < chunk_size) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "block of type %u in pcap-ng dump file is too short", cursor->block_type); return (NULL); } /* * Return the current pointer, and skip past the chunk. */ data = cursor->data; cursor->data += chunk_size; cursor->data_remaining -= chunk_size; return (data); } static struct option_header * get_opthdr_from_block_data(pcap_t *p, struct block_cursor *cursor, char *errbuf) { struct option_header *opthdr; opthdr = get_from_block_data(cursor, sizeof(*opthdr), errbuf); if (opthdr == NULL) { /* * Option header is cut short. */ return (NULL); } /* * Byte-swap it if necessary. */ if (p->swapped) { opthdr->option_code = SWAPSHORT(opthdr->option_code); opthdr->option_length = SWAPSHORT(opthdr->option_length); } return (opthdr); } static void * get_optvalue_from_block_data(struct block_cursor *cursor, struct option_header *opthdr, char *errbuf) { size_t padded_option_len; void *optvalue; /* Pad option length to 4-byte boundary */ padded_option_len = opthdr->option_length; padded_option_len = ((padded_option_len + 3)/4)*4; optvalue = get_from_block_data(cursor, padded_option_len, errbuf); if (optvalue == NULL) { /* * Option value is cut short. */ return (NULL); } return (optvalue); } static int process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, u_int64_t *tsoffset, int *is_binary, char *errbuf) { struct option_header *opthdr; void *optvalue; int saw_tsresol, saw_tsoffset; u_char tsresol_opt; u_int i; saw_tsresol = 0; saw_tsoffset = 0; while (cursor->data_remaining != 0) { /* * Get the option header. */ opthdr = get_opthdr_from_block_data(p, cursor, errbuf); if (opthdr == NULL) { /* * Option header is cut short. */ return (-1); } /* * Get option value. */ optvalue = get_optvalue_from_block_data(cursor, opthdr, errbuf); if (optvalue == NULL) { /* * Option value is cut short. */ return (-1); } switch (opthdr->option_code) { case OPT_ENDOFOPT: if (opthdr->option_length != 0) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has opt_endofopt option with length %u != 0", opthdr->option_length); return (-1); } goto done; case IF_TSRESOL: if (opthdr->option_length != 1) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has if_tsresol option with length %u != 1", opthdr->option_length); return (-1); } if (saw_tsresol) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsresol option"); return (-1); } saw_tsresol = 1; memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt)); if (tsresol_opt & 0x80) { /* * Resolution is negative power of 2. */ *is_binary = 1; *tsresol = 1 << (tsresol_opt & 0x7F); } else { /* * Resolution is negative power of 10. */ *is_binary = 0; *tsresol = 1; for (i = 0; i < tsresol_opt; i++) *tsresol *= 10; } if (*tsresol == 0) { /* * Resolution is too high. */ if (tsresol_opt & 0x80) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 2^-%u is too high", tsresol_opt & 0x7F); } else { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 10^-%u is too high", tsresol_opt); } return (-1); } break; case IF_TSOFFSET: if (opthdr->option_length != 8) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has if_tsoffset option with length %u != 8", opthdr->option_length); return (-1); } if (saw_tsoffset) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsoffset option"); return (-1); } saw_tsoffset = 1; memcpy(tsoffset, optvalue, sizeof(*tsoffset)); if (p->swapped) *tsoffset = SWAPLL(*tsoffset); break; default: break; } } done: return (0); } static int add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf) { struct pcap_ng_sf *ps; u_int tsresol; u_int64_t tsoffset; int is_binary; ps = p->priv; /* * Count this interface. */ ps->ifcount++; /* * Grow the array of per-interface information as necessary. */ if (ps->ifcount > ps->ifaces_size) { /* * We need to grow the array. */ bpf_u_int32 new_ifaces_size; struct pcap_ng_if *new_ifaces; if (ps->ifaces_size == 0) { /* * It's currently empty. * * (The Clang static analyzer doesn't do enough, * err, umm, dataflow *analysis* to realize that * ps->ifaces_size == 0 if ps->ifaces == NULL, * and so complains about a possible zero argument * to realloc(), so we check for the former * condition to shut it up. * * However, it doesn't complain that one of the * multiplications below could overflow, which is * a real, albeit extremely unlikely, problem (you'd * need a pcap-ng file with tens of millions of * interfaces).) */ new_ifaces_size = 1; new_ifaces = malloc(sizeof (struct pcap_ng_if)); } else { /* * It's not currently empty; double its size. * (Perhaps overkill once we have a lot of interfaces.) * * Check for overflow if we double it. */ if (ps->ifaces_size * 2 < ps->ifaces_size) { /* * The maximum number of interfaces before * ps->ifaces_size overflows is the largest * possible 32-bit power of 2, as we do * size doubling. */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "more than %u interfaces in the file", 0x80000000U); return (0); } /* * ps->ifaces_size * 2 doesn't overflow, so it's * safe to multiply. */ new_ifaces_size = ps->ifaces_size * 2; /* * Now make sure that's not so big that it overflows * if we multiply by sizeof (struct pcap_ng_if). * * That can happen on 32-bit platforms, with a 32-bit * size_t; it shouldn't happen on 64-bit platforms, * with a 64-bit size_t, as new_ifaces_size is * 32 bits. */ if (new_ifaces_size * sizeof (struct pcap_ng_if) < new_ifaces_size) { /* * As this fails only with 32-bit size_t, * the multiplication was 32x32->32, and * the largest 32-bit value that can safely * be multiplied by sizeof (struct pcap_ng_if) * without overflow is the largest 32-bit * (unsigned) value divided by * sizeof (struct pcap_ng_if). */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "more than %u interfaces in the file", 0xFFFFFFFFU / ((u_int)sizeof (struct pcap_ng_if))); return (0); } new_ifaces = realloc(ps->ifaces, new_ifaces_size * sizeof (struct pcap_ng_if)); } if (new_ifaces == NULL) { /* * We ran out of memory. * Give up. */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory for per-interface information (%u interfaces)", ps->ifcount); return (0); } ps->ifaces_size = new_ifaces_size; ps->ifaces = new_ifaces; } /* * Set the default time stamp resolution and offset. */ tsresol = 1000000; /* microsecond resolution */ is_binary = 0; /* which is a power of 10 */ tsoffset = 0; /* absolute timestamps */ /* * Now look for various time stamp options, so we know * how to interpret the time stamps for this interface. */ if (process_idb_options(p, cursor, &tsresol, &tsoffset, &is_binary, errbuf) == -1) return (0); ps->ifaces[ps->ifcount - 1].tsresol = tsresol; ps->ifaces[ps->ifcount - 1].tsoffset = tsoffset; /* * Determine whether we're scaling up or down or not * at all for this interface. */ if (tsresol == ps->user_tsresol) { /* * The resolution is the resolution the user wants, * so we don't have to do scaling. */ ps->ifaces[ps->ifcount - 1].scale_type = PASS_THROUGH; } else if (tsresol > ps->user_tsresol) { /* * The resolution is greater than what the user wants, * so we have to scale the timestamps down. */ if (is_binary) ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN_BIN; else { /* * Calculate the scale factor. */ ps->ifaces[ps->ifcount - 1].scale_factor = tsresol/ps->user_tsresol; ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN_DEC; } } else { /* * The resolution is less than what the user wants, * so we have to scale the timestamps up. */ if (is_binary) ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP_BIN; else { /* * Calculate the scale factor. */ ps->ifaces[ps->ifcount - 1].scale_factor = ps->user_tsresol/tsresol; ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP_DEC; } } return (1); } /* * Check whether this is a pcap-ng savefile and, if it is, extract the * relevant information from the header. */ pcap_t * pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, int *err) { size_t amt_read; bpf_u_int32 total_length; bpf_u_int32 byte_order_magic; struct block_header *bhdrp; struct section_header_block *shbp; pcap_t *p; int swapped = 0; struct pcap_ng_sf *ps; int status; struct block_cursor cursor; struct interface_description_block *idbp; /* * Assume no read errors. */ *err = 0; /* * Check whether the first 4 bytes of the file are the block * type for a pcap-ng savefile. */ if (magic != BT_SHB) { /* * XXX - check whether this looks like what the block * type would be after being munged by mapping between * UN*X and DOS/Windows text file format and, if it * does, look for the byte-order magic number in * the appropriate place and, if we find it, report * this as possibly being a pcap-ng file transferred * between UN*X and Windows in text file format? */ return (NULL); /* nope */ } /* * OK, they are. However, that's just \n\r\r\n, so it could, * conceivably, be an ordinary text file. * * It could not, however, conceivably be any other type of * capture file, so we can read the rest of the putative * Section Header Block; put the block type in the common * header, read the rest of the common header and the * fixed-length portion of the SHB, and look for the byte-order * magic value. */ amt_read = fread(&total_length, 1, sizeof(total_length), fp); if (amt_read < sizeof(total_length)) { if (ferror(fp)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); *err = 1; return (NULL); /* fail */ } /* * Possibly a weird short text file, so just say * "not pcap-ng". */ return (NULL); } amt_read = fread(&byte_order_magic, 1, sizeof(byte_order_magic), fp); if (amt_read < sizeof(byte_order_magic)) { if (ferror(fp)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); *err = 1; return (NULL); /* fail */ } /* * Possibly a weird short text file, so just say * "not pcap-ng". */ return (NULL); } if (byte_order_magic != BYTE_ORDER_MAGIC) { byte_order_magic = SWAPLONG(byte_order_magic); if (byte_order_magic != BYTE_ORDER_MAGIC) { /* * Not a pcap-ng file. */ return (NULL); } swapped = 1; total_length = SWAPLONG(total_length); } /* * Check the sanity of the total length. */ if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Section Header Block in pcap-ng dump file has a length of %u < %lu", total_length, (unsigned long)(sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer))); *err = 1; return (NULL); } /* * OK, this is a good pcap-ng file. * Allocate a pcap_t for it. */ p = pcap_open_offline_common(errbuf, sizeof (struct pcap_ng_sf)); if (p == NULL) { /* Allocation failed. */ *err = 1; return (NULL); } p->swapped = swapped; ps = p->priv; /* * What precision does the user want? */ switch (precision) { case PCAP_TSTAMP_PRECISION_MICRO: ps->user_tsresol = 1000000; break; case PCAP_TSTAMP_PRECISION_NANO: ps->user_tsresol = 1000000000; break; default: pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown time stamp resolution %u", precision); free(p); *err = 1; return (NULL); } p->opt.tstamp_precision = precision; /* * Allocate a buffer into which to read blocks. We default to * the maximum of: * * the total length of the SHB for which we read the header; * * 2K, which should be more than large enough for an Enhanced * Packet Block containing a full-size Ethernet frame, and * leaving room for some options. * * If we find a bigger block, we reallocate the buffer. */ p->bufsize = 2048; if (p->bufsize < total_length) p->bufsize = total_length; p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); free(p); *err = 1; return (NULL); } /* * Copy the stuff we've read to the buffer, and read the rest * of the SHB. */ bhdrp = (struct block_header *)p->buffer; shbp = (struct section_header_block *)((u_char *)p->buffer + sizeof(struct block_header)); bhdrp->block_type = magic; bhdrp->total_length = total_length; shbp->byte_order_magic = byte_order_magic; if (read_bytes(fp, (u_char *)p->buffer + (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), total_length - (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), 1, errbuf) == -1) goto fail; if (p->swapped) { /* * Byte-swap the fields we've read. */ shbp->major_version = SWAPSHORT(shbp->major_version); shbp->minor_version = SWAPSHORT(shbp->minor_version); /* * XXX - we don't care about the section length. */ } /* currently only SHB version 1.0 is supported */ if (! (shbp->major_version == PCAP_NG_VERSION_MAJOR && shbp->minor_version == PCAP_NG_VERSION_MINOR)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unsupported pcap-ng savefile version %u.%u", shbp->major_version, shbp->minor_version); goto fail; } p->version_major = shbp->major_version; p->version_minor = shbp->minor_version; /* * Save the time stamp resolution the user requested. */ p->opt.tstamp_precision = precision; /* * Now start looking for an Interface Description Block. */ for (;;) { /* * Read the next block. */ status = read_block(fp, p, &cursor, errbuf); if (status == 0) { /* EOF - no IDB in this file */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "the capture file has no Interface Description Blocks"); goto fail; } if (status == -1) goto fail; /* error */ switch (cursor.block_type) { case BT_IDB: /* * Get a pointer to the fixed-length portion of the * IDB. */ idbp = get_from_block_data(&cursor, sizeof(*idbp), errbuf); if (idbp == NULL) goto fail; /* error */ /* * Byte-swap it if necessary. */ if (p->swapped) { idbp->linktype = SWAPSHORT(idbp->linktype); idbp->snaplen = SWAPLONG(idbp->snaplen); } /* * Interface capture length sanity check */ if (idbp->snaplen > MAXIMUM_SNAPLEN) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "invalid interface capture length %u, " "bigger than maximum of %u", idbp->snaplen, MAXIMUM_SNAPLEN); goto fail; } /* * Try to add this interface. */ if (!add_interface(p, &cursor, errbuf)) goto fail; goto done; case BT_EPB: case BT_SPB: case BT_PB: /* * Saw a packet before we saw any IDBs. That's * not valid, as we don't know what link-layer * encapsulation the packet has. */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "the capture file has a packet block before any Interface Description Blocks"); goto fail; default: /* * Just ignore it. */ break; } } done: p->tzoff = 0; /* XXX - not used in pcap */ p->snapshot = idbp->snaplen; p->linktype = linktype_to_dlt(idbp->linktype); p->linktype_ext = 0; p->next_packet_op = pcap_ng_next_packet; p->cleanup_op = pcap_ng_cleanup; return (p); fail: free(ps->ifaces); free(p->buffer); free(p); *err = 1; return (NULL); } static void pcap_ng_cleanup(pcap_t *p) { struct pcap_ng_sf *ps = p->priv; free(ps->ifaces); sf_cleanup(p); } /* * Read and return the next packet from the savefile. Return the header * in hdr and a pointer to the contents in data. Return 0 on success, 1 * if there were no more packets, and -1 on an error. */ static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) { struct pcap_ng_sf *ps = p->priv; struct block_cursor cursor; int status; struct enhanced_packet_block *epbp; struct simple_packet_block *spbp; struct packet_block *pbp; bpf_u_int32 interface_id = 0xFFFFFFFF; struct interface_description_block *idbp; struct section_header_block *shbp; FILE *fp = p->rfile; u_int64_t t, sec, frac; /* * Look for an Enhanced Packet Block, a Simple Packet Block, * or a Packet Block. */ for (;;) { /* * Read the block type and length; those are common * to all blocks. */ status = read_block(fp, p, &cursor, p->errbuf); if (status == 0) return (1); /* EOF */ if (status == -1) return (-1); /* error */ switch (cursor.block_type) { case BT_EPB: /* * Get a pointer to the fixed-length portion of the * EPB. */ epbp = get_from_block_data(&cursor, sizeof(*epbp), p->errbuf); if (epbp == NULL) return (-1); /* error */ /* * Byte-swap it if necessary. */ if (p->swapped) { /* these were written in opposite byte order */ interface_id = SWAPLONG(epbp->interface_id); hdr->caplen = SWAPLONG(epbp->caplen); hdr->len = SWAPLONG(epbp->len); t = ((u_int64_t)SWAPLONG(epbp->timestamp_high)) << 32 | SWAPLONG(epbp->timestamp_low); } else { interface_id = epbp->interface_id; hdr->caplen = epbp->caplen; hdr->len = epbp->len; t = ((u_int64_t)epbp->timestamp_high) << 32 | epbp->timestamp_low; } goto found; case BT_SPB: /* * Get a pointer to the fixed-length portion of the * SPB. */ spbp = get_from_block_data(&cursor, sizeof(*spbp), p->errbuf); if (spbp == NULL) return (-1); /* error */ /* * SPB packets are assumed to have arrived on * the first interface. */ interface_id = 0; /* * Byte-swap it if necessary. */ if (p->swapped) { /* these were written in opposite byte order */ hdr->len = SWAPLONG(spbp->len); } else hdr->len = spbp->len; /* * The SPB doesn't give the captured length; * it's the minimum of the snapshot length * and the packet length. */ hdr->caplen = hdr->len; if (hdr->caplen > (bpf_u_int32)p->snapshot) hdr->caplen = p->snapshot; t = 0; /* no time stamps */ goto found; case BT_PB: /* * Get a pointer to the fixed-length portion of the * PB. */ pbp = get_from_block_data(&cursor, sizeof(*pbp), p->errbuf); if (pbp == NULL) return (-1); /* error */ /* * Byte-swap it if necessary. */ if (p->swapped) { /* these were written in opposite byte order */ interface_id = SWAPSHORT(pbp->interface_id); hdr->caplen = SWAPLONG(pbp->caplen); hdr->len = SWAPLONG(pbp->len); t = ((u_int64_t)SWAPLONG(pbp->timestamp_high)) << 32 | SWAPLONG(pbp->timestamp_low); } else { interface_id = pbp->interface_id; hdr->caplen = pbp->caplen; hdr->len = pbp->len; t = ((u_int64_t)pbp->timestamp_high) << 32 | pbp->timestamp_low; } goto found; case BT_IDB: /* * Interface Description Block. Get a pointer * to its fixed-length portion. */ idbp = get_from_block_data(&cursor, sizeof(*idbp), p->errbuf); if (idbp == NULL) return (-1); /* error */ /* * Byte-swap it if necessary. */ if (p->swapped) { idbp->linktype = SWAPSHORT(idbp->linktype); idbp->snaplen = SWAPLONG(idbp->snaplen); } /* * If the link-layer type or snapshot length * differ from the ones for the first IDB we * saw, quit. * * XXX - just discard packets from those * interfaces? */ if (p->linktype != idbp->linktype) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "an interface has a type %u different from the type of the first interface", idbp->linktype); return (-1); } if ((bpf_u_int32)p->snapshot != idbp->snaplen) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "an interface has a snapshot length %u different from the type of the first interface", idbp->snaplen); return (-1); } /* * Try to add this interface. */ if (!add_interface(p, &cursor, p->errbuf)) return (-1); break; case BT_SHB: /* * Section Header Block. Get a pointer * to its fixed-length portion. */ shbp = get_from_block_data(&cursor, sizeof(*shbp), p->errbuf); if (shbp == NULL) return (-1); /* error */ /* * Assume the byte order of this section is * the same as that of the previous section. * We'll check for that later. */ if (p->swapped) { shbp->byte_order_magic = SWAPLONG(shbp->byte_order_magic); shbp->major_version = SWAPSHORT(shbp->major_version); } /* * Make sure the byte order doesn't change; * pcap_is_swapped() shouldn't change its * return value in the middle of reading a capture. */ switch (shbp->byte_order_magic) { case BYTE_ORDER_MAGIC: /* * OK. */ break; case SWAPLONG(BYTE_ORDER_MAGIC): /* * Byte order changes. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "the file has sections with different byte orders"); return (-1); default: /* * Not a valid SHB. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "the file has a section with a bad byte order magic field"); return (-1); } /* * Make sure the major version is the version * we handle. */ if (shbp->major_version != PCAP_NG_VERSION_MAJOR) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown pcap-ng savefile major version number %u", shbp->major_version); return (-1); } /* * Reset the interface count; this section should * have its own set of IDBs. If any of them * don't have the same interface type, snapshot * length, or resolution as the first interface * we saw, we'll fail. (And if we don't see * any IDBs, we'll fail when we see a packet * block.) */ ps->ifcount = 0; break; default: /* * Not a packet block, IDB, or SHB; ignore it. */ break; } } found: /* * Is the interface ID an interface we know? */ if (interface_id >= ps->ifcount) { /* * Yes. Fail. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "a packet arrived on interface %u, but there's no Interface Description Block for that interface", interface_id); return (-1); } /* * Convert the time stamp to seconds and fractions of a second, * with the fractions being in units of the file-supplied resolution. */ sec = t / ps->ifaces[interface_id].tsresol + ps->ifaces[interface_id].tsoffset; frac = t % ps->ifaces[interface_id].tsresol; /* * Convert the fractions from units of the file-supplied resolution * to units of the user-requested resolution. */ switch (ps->ifaces[interface_id].scale_type) { case PASS_THROUGH: /* * The interface resolution is what the user wants, * so we're done. */ break; case SCALE_UP_DEC: /* * The interface resolution is less than what the user * wants; scale the fractional part up to the units of * the resolution the user requested by multiplying by * the quotient of the user-requested resolution and the * file-supplied resolution. * * Those resolutions are both powers of 10, and the user- * requested resolution is greater than the file-supplied * resolution, so the quotient in question is an integer. * We've calculated that quotient already, so we just * multiply by it. */ frac *= ps->ifaces[interface_id].scale_factor; break; case SCALE_UP_BIN: /* * The interface resolution is less than what the user * wants; scale the fractional part up to the units of * the resolution the user requested by multiplying by * the quotient of the user-requested resolution and the * file-supplied resolution. * * The file-supplied resolution is a power of 2, so the * quotient is not an integer, so, in order to do this * entirely with integer arithmetic, we multiply by the * user-requested resolution and divide by the file- * supplied resolution. * * XXX - Is there something clever we could do here, * given that we know that the file-supplied resolution * is a power of 2? Doing a multiplication followed by * a division runs the risk of overflowing, and involves * two non-simple arithmetic operations. */ frac *= ps->user_tsresol; frac /= ps->ifaces[interface_id].tsresol; break; case SCALE_DOWN_DEC: /* * The interface resolution is greater than what the user * wants; scale the fractional part up to the units of * the resolution the user requested by multiplying by * the quotient of the user-requested resolution and the * file-supplied resolution. * * Those resolutions are both powers of 10, and the user- * requested resolution is less than the file-supplied * resolution, so the quotient in question isn't an * integer, but its reciprocal is, and we can just divide * by the reciprocal of the quotient. We've calculated * the reciprocal of that quotient already, so we must * divide by it. */ frac /= ps->ifaces[interface_id].scale_factor; break; case SCALE_DOWN_BIN: /* * The interface resolution is greater than what the user * wants; convert the fractional part to units of the * resolution the user requested by multiplying by the * quotient of the user-requested resolution and the * file-supplied resolution. We do that by multiplying * by the user-requested resolution and dividing by the * file-supplied resolution, as the quotient might not * fit in an integer. * * The file-supplied resolution is a power of 2, so the * quotient is not an integer, and neither is its * reciprocal, so, in order to do this entirely with * integer arithmetic, we multiply by the user-requested * resolution and divide by the file-supplied resolution. * * XXX - Is there something clever we could do here, * given that we know that the file-supplied resolution * is a power of 2? Doing a multiplication followed by * a division runs the risk of overflowing, and involves * two non-simple arithmetic operations. */ frac *= ps->user_tsresol; frac /= ps->ifaces[interface_id].tsresol; break; } #ifdef _WIN32 /* * tv_sec and tv_used in the Windows struct timeval are both * longs. */ hdr->ts.tv_sec = (long)sec; hdr->ts.tv_usec = (long)frac; #else /* * tv_sec in the UN*X struct timeval is a time_t; tv_usec is * suseconds_t in UN*Xes that work the way the current Single * UNIX Standard specify - but not all older UN*Xes necessarily * support that type, so just cast to int. */ hdr->ts.tv_sec = (time_t)sec; hdr->ts.tv_usec = (int)frac; #endif /* * Get a pointer to the packet data. */ *data = get_from_block_data(&cursor, hdr->caplen, p->errbuf); if (*data == NULL) return (-1); if (p->swapped) swap_pseudo_headers(p->linktype, hdr, *data); return (0); } libpcap-1.8.1/pcap-dbus.c0000644000026300017510000001706313003771737013317 0ustar mcrmcr/* * Copyright (c) 2012 Jakub Zawadzki * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "pcap-int.h" #include "pcap-dbus.h" /* * Private data for capturing on D-Bus. */ struct pcap_dbus { DBusConnection *conn; u_int packets_read; /* count of packets read */ }; static int dbus_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_dbus *handlep = handle->priv; struct pcap_pkthdr pkth; DBusMessage *message; char *raw_msg; int raw_msg_len; int count = 0; message = dbus_connection_pop_message(handlep->conn); while (!message) { /* XXX handle->opt.timeout = timeout_ms; */ if (!dbus_connection_read_write(handlep->conn, 100)) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Connection closed"); return -1; } if (handle->break_loop) { handle->break_loop = 0; return -2; } message = dbus_connection_pop_message(handlep->conn); } if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Disconnected"); return -1; } if (dbus_message_marshal(message, &raw_msg, &raw_msg_len)) { pkth.caplen = pkth.len = raw_msg_len; /* pkth.caplen = min (payload_len, handle->snapshot); */ gettimeofday(&pkth.ts, NULL); if (handle->fcode.bf_insns == NULL || bpf_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) { handlep->packets_read++; callback(user, &pkth, (u_char *)raw_msg); count++; } dbus_free(raw_msg); } return count; } static int dbus_write(pcap_t *handle, const void *buf, size_t size) { /* XXX, not tested */ struct pcap_dbus *handlep = handle->priv; DBusError error = DBUS_ERROR_INIT; DBusMessage *msg; if (!(msg = dbus_message_demarshal(buf, size, &error))) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dbus_message_demarshal() failed: %s", error.message); dbus_error_free(&error); return -1; } dbus_connection_send(handlep->conn, msg, NULL); dbus_connection_flush(handlep->conn); dbus_message_unref(msg); return 0; } static int dbus_stats(pcap_t *handle, struct pcap_stat *stats) { struct pcap_dbus *handlep = handle->priv; stats->ps_recv = handlep->packets_read; stats->ps_drop = 0; stats->ps_ifdrop = 0; return 0; } static void dbus_cleanup(pcap_t *handle) { struct pcap_dbus *handlep = handle->priv; dbus_connection_unref(handlep->conn); pcap_cleanup_live_common(handle); } static int dbus_activate(pcap_t *handle) { #define EAVESDROPPING_RULE "eavesdrop=true," static const char *rules[] = { EAVESDROPPING_RULE "type='signal'", EAVESDROPPING_RULE "type='method_call'", EAVESDROPPING_RULE "type='method_return'", EAVESDROPPING_RULE "type='error'", }; #define N_RULES sizeof(rules)/sizeof(rules[0]) struct pcap_dbus *handlep = handle->priv; const char *dev = handle->opt.device; DBusError error = DBUS_ERROR_INIT; u_int i; if (strcmp(dev, "dbus-system") == 0) { if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get system bus: %s", error.message); dbus_error_free(&error); return PCAP_ERROR; } } else if (strcmp(dev, "dbus-session") == 0) { if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SESSION, &error))) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get session bus: %s", error.message); dbus_error_free(&error); return PCAP_ERROR; } } else if (strncmp(dev, "dbus://", 7) == 0) { const char *addr = dev + 7; if (!(handlep->conn = dbus_connection_open(addr, &error))) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to open connection to: %s: %s", addr, error.message); dbus_error_free(&error); return PCAP_ERROR; } if (!dbus_bus_register(handlep->conn, &error)) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to register bus %s: %s\n", addr, error.message); dbus_error_free(&error); return PCAP_ERROR; } } else { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get bus address from %s", handle->opt.device); return PCAP_ERROR; } /* Initialize some components of the pcap structure. */ handle->bufsize = 0; handle->offset = 0; handle->linktype = DLT_DBUS; handle->read_op = dbus_read; handle->inject_op = dbus_write; handle->setfilter_op = install_bpf_program; /* XXX, later add support for dbus_bus_add_match() */ handle->setdirection_op = NULL; handle->set_datalink_op = NULL; /* can't change data link type */ handle->getnonblock_op = pcap_getnonblock_fd; handle->setnonblock_op = pcap_setnonblock_fd; handle->stats_op = dbus_stats; handle->selectable_fd = handle->fd = -1; if (handle->opt.rfmon) { /* * Monitor mode doesn't apply to dbus connections. */ dbus_cleanup(handle); return PCAP_ERROR_RFMON_NOTSUP; } /* dbus_connection_set_max_message_size(handlep->conn, handle->snapshot); */ if (handle->opt.buffer_size != 0) dbus_connection_set_max_received_size(handlep->conn, handle->opt.buffer_size); for (i = 0; i < N_RULES; i++) { dbus_bus_add_match(handlep->conn, rules[i], &error); if (dbus_error_is_set(&error)) { dbus_error_free(&error); /* try without eavesdrop */ dbus_bus_add_match(handlep->conn, rules[i] + strlen(EAVESDROPPING_RULE), &error); if (dbus_error_is_set(&error)) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to add bus match: %s\n", error.message); dbus_error_free(&error); dbus_cleanup(handle); return PCAP_ERROR; } } } return 0; } pcap_t * dbus_create(const char *device, char *ebuf, int *is_ours) { pcap_t *p; if (strcmp(device, "dbus-system") && strcmp(device, "dbus-session") && strncmp(device, "dbus://", 7)) { *is_ours = 0; return NULL; } *is_ours = 1; p = pcap_create_common(ebuf, sizeof (struct pcap_dbus)); if (p == NULL) return (NULL); p->activate_op = dbus_activate; return (p); } int dbus_findalldevs(pcap_if_t **alldevsp, char *err_str) { if (pcap_add_if(alldevsp, "dbus-system", 0, "D-Bus system bus", err_str) < 0) return -1; if (pcap_add_if(alldevsp, "dbus-session", 0, "D-Bus session bus", err_str) < 0) return -1; return 0; } libpcap-1.8.1/msdos/0000755000026300017510000000000013003775545012414 5ustar mcrmcrlibpcap-1.8.1/msdos/pktdrvr.h0000644000026300017510000001234313003771737014263 0ustar mcrmcr#ifndef __PKTDRVR_H #define __PKTDRVR_H #define PUBLIC #define LOCAL static #define RX_BUF_SIZE ETH_MTU /* buffer size variables. NB !! */ #define TX_BUF_SIZE ETH_MTU /* must be same as in pkt_rx*.* */ #ifdef __HIGHC__ #pragma Off(Align_members) #else #pragma pack(1) #endif typedef enum { /* Packet-driver classes */ PD_ETHER = 1, PD_PRONET10 = 2, PD_IEEE8025 = 3, PD_OMNINET = 4, PD_APPLETALK = 5, PD_SLIP = 6, PD_STARTLAN = 7, PD_ARCNET = 8, PD_AX25 = 9, PD_KISS = 10, PD_IEEE8023_2 = 11, PD_FDDI8022 = 12, PD_X25 = 13, PD_LANstar = 14, PD_PPP = 18 } PKT_CLASS; typedef enum { /* Packet-driver receive modes */ PDRX_OFF = 1, /* turn off receiver */ PDRX_DIRECT, /* receive only to this interface */ PDRX_BROADCAST, /* DIRECT + broadcast packets */ PDRX_MULTICAST1, /* BROADCAST + limited multicast */ PDRX_MULTICAST2, /* BROADCAST + all multicast */ PDRX_ALL_PACKETS, /* receive all packets on network */ } PKT_RX_MODE; typedef struct { char type[8]; char len; } PKT_FRAME; typedef struct { BYTE class; /* = 1 for DEC/Interl/Xerox Ethernet */ BYTE number; /* = 0 for single LAN adapter */ WORD type; /* = 13 for 3C523 */ BYTE funcs; /* Basic/Extended/HiPerf functions */ WORD intr; /* user interrupt vector number */ WORD handle; /* Handle associated with session */ BYTE name [15]; /* Name of adapter interface,ie.3C523*/ BOOL quiet; /* (don't) print errors to stdout */ const char *error; /* address of error string */ BYTE majVer; /* Major driver implementation ver. */ BYTE minVer; /* Minor driver implementation ver. */ BYTE dummyLen; /* length of following data */ WORD MAClength; /* HiPerformance data, N/A */ WORD MTU; /* HiPerformance data, N/A */ WORD multicast; /* HiPerformance data, N/A */ WORD rcvrBuffers; /* valid for */ WORD UMTbufs; /* High Performance drivers only */ WORD postEOIintr; /* Usage ?? */ } PKT_INFO; #define PKT_PARAM_SIZE 14 /* members majVer - postEOIintr */ typedef struct { DWORD inPackets; /* # of packets received */ DWORD outPackets; /* # of packets transmitted */ DWORD inBytes; /* # of bytes received */ DWORD outBytes; /* # of bytes transmitted */ DWORD inErrors; /* # of reception errors */ DWORD outErrors; /* # of transmission errors */ DWORD lost; /* # of packets lost (RX) */ } PKT_STAT; typedef struct { ETHER destin; ETHER source; WORD proto; BYTE data [TX_BUF_SIZE]; } TX_ELEMENT; typedef struct { WORD firstCount; /* # of bytes on 1st */ WORD secondCount; /* and 2nd upcall */ WORD handle; /* instance that upcalled */ ETHER destin; /* E-net destination address */ ETHER source; /* E-net source address */ WORD proto; /* protocol number */ BYTE data [RX_BUF_SIZE]; } RX_ELEMENT; #ifdef __HIGHC__ #pragma pop(Align_members) #else #pragma pack() #endif /* * Prototypes for publics */ #ifdef __cplusplus extern "C" { #endif extern PKT_STAT pktStat; /* statistics for packets */ extern PKT_INFO pktInfo; /* packet-driver information */ extern PKT_RX_MODE receiveMode; extern ETHER myAddress, ethBroadcast; extern BOOL PktInitDriver (PKT_RX_MODE mode); extern BOOL PktExitDriver (void); extern const char *PktGetErrorStr (int errNum); extern const char *PktGetClassName (WORD class); extern const char *PktRXmodeStr (PKT_RX_MODE mode); extern BOOL PktSearchDriver (void); extern int PktReceive (BYTE *buf, int max); extern BOOL PktTransmit (const void *eth, int len); extern DWORD PktRxDropped (void); extern BOOL PktReleaseHandle (WORD handle); extern BOOL PktTerminHandle (WORD handle); extern BOOL PktResetInterface (WORD handle); extern BOOL PktSetReceiverMode(PKT_RX_MODE mode); extern BOOL PktGetReceiverMode(PKT_RX_MODE *mode); extern BOOL PktGetStatistics (WORD handle); extern BOOL PktSessStatistics (WORD handle); extern BOOL PktResetStatistics(WORD handle); extern BOOL PktGetAddress (ETHER *addr); extern BOOL PktSetAddress (const ETHER *addr); extern BOOL PktGetDriverInfo (void); extern BOOL PktGetDriverParam (void); extern void PktQueueBusy (BOOL busy); extern WORD PktBuffersUsed (void); #ifdef __cplusplus } #endif #endif /* __PKTDRVR_H */ libpcap-1.8.1/msdos/pkt_rx0.asm0000644000026300017510000001371713003771737014515 0ustar mcrmcrPAGE 60,132 NAME PKT_RX ifdef ??version ; using TASM masm jumps endif PUBLIC _pktDrop, _pktRxBuf, _pktTxBuf, _pktTemp PUBLIC _rxOutOfs, _rxInOfs, _PktReceiver, _pktRxEnd ; ; these sizes MUST be equal to the sizes in PKTDRVR.H ; RX_BUF_SIZE = 1500 ; max message size on Ethernet TX_BUF_SIZE = 1500 ifdef DOSX .386 NUM_RX_BUF = 32 ; # of RX element buffers _TEXT SEGMENT PUBLIC DWORD USE16 'CODE' _TEXT ENDS _DATA SEGMENT PUBLIC DWORD USE16 'CODE' _DATA ENDS D_SEG EQU <_TEXT SEGMENT> D_END EQU <_TEXT ENDS> ASSUME CS:_TEXT,DS:_TEXT else .286 NUM_RX_BUF = 10 _TEXT SEGMENT PUBLIC DWORD 'CODE' _TEXT ENDS _DATA SEGMENT PUBLIC DWORD 'DATA' _DATA ENDS D_SEG EQU <_DATA SEGMENT> D_END EQU <_DATA ENDS> ASSUME CS:_TEXT,DS:_DATA endif ;------------------------------------------- D_SEG RX_ELEMENT STRUC firstCount dw 0 ; # of bytes on 1st call secondCount dw 0 ; # of bytes on 2nd call handle dw 0 ; handle for upcall destinAdr db 6 dup (0) ; packet destination address sourceAdr db 6 dup (0) ; packet source address protocol dw 0 ; packet protocol number rxBuffer db RX_BUF_SIZE dup (0) ; RX buffer ENDS align 4 _rxOutOfs dw offset _pktRxBuf ; ring buffer offsets _rxInOfs dw offset _pktRxBuf ; into _pktRxBuf _pktDrop dw 0,0 ; packet drop counter _pktTemp db 20 dup (0) ; temp work area _pktTxBuf db (TX_BUF_SIZE+14) dup (0) ; TX buffer _pktRxBuf RX_ELEMENT NUM_RX_BUF dup (<>) ; RX structures LAST_OFS = offset $ screenSeg dw 0B800h newInOffset dw 0 fanChars db '-\|/' fanIndex dw 0 D_END _TEXT SEGMENT SHOW_RX MACRO push es push bx mov bx, screenSeg mov es, bx ;; r-mode segment of colour screen mov di, 158 ;; upper right corner - 1 mov bx, fanIndex mov al, fanChars[bx] ;; get write char mov ah, 15 ;; and white colour stosw ;; write to screen at ES:EDI inc fanIndex ;; update next index and fanIndex, 3 pop bx pop es ENDM ;------------------------------------------------------------------------ ; ; This macro return ES:DI to tail of Rx queue ENQUEUE MACRO LOCAL @noWrap mov ax, _rxInOfs ;; DI = current in-offset add ax, SIZE RX_ELEMENT ;; point to next _pktRxBuf buffer cmp ax, LAST_OFS ;; pointing past last ? jb @noWrap ;; no - jump lea ax, _pktRxBuf ;; yes, point to 1st buffer align 4 @noWrap: cmp ax, _rxOutOfs ;; in-ofs = out-ofs ? je @dump ;; yes, queue is full mov di, _rxInOfs ;; ES:DI -> buffer at queue input mov newInOffset, ax ;; remember new input offset ;; NOTE. rxInOfs is updated after the packet has been copied ;; to ES:DI (= DS:SI on 2nd call) by the packet driver ENDM ;------------------------------------------------------------------------ ; ; This routine gets called by the packet driver twice: ; 1st time (AX=0) it requests an address where to put the packet ; ; 2nd time (AX=1) the packet has been copied to this location (DS:SI) ; BX has client handle (stored in RX_ELEMENT.handle). ; CX has # of bytes in packet on both call. They should be equal. ; ; A test for equality is done by putting CX in _pktRxBuf [n].firstCount ; and _pktRxBuf[n].secondCount, and CL on first call in ; _pktRxBuf[n].rxBuffer[CX]. These values are checked in "PktReceive" ; (PKTDRVR.C) ; ;--------------------------------------------------------------------- _PktReceiver: pushf cli ; no distraction wanted ! push ds push bx ifdef DOSX mov bx, cs else mov bx, SEG _DATA endif mov ds, bx mov es, bx ; ES = DS = CS or seg _DATA pop bx ; restore handle cmp ax, 0 ; first call? (AX=0) jne @post ; AX=1: second call, do post process ifdef DEBUG SHOW_RX ; show that a packet is received endif cmp cx, RX_BUF_SIZE+14 ; size OK ? ja @skip ; no, packet to large for us ENQUEUE ; ES:DI -> _pktRxBuf[n] mov [di].firstCount, cx ; remember the first count. mov [di].handle, bx ; remember the handle. add di, 6 ; ES:DI -> _pktRxBuf[n].destinAdr pop ds popf retf ; far return to driver with ES:DI align 4 @dump: inc _pktDrop[0] ; discard the packet on 1st call adc _pktDrop[2], 0 ; increment packets lost @skip: xor di, di ; return ES:DI = NIL pointer xor ax, ax mov es, ax pop ds popf retf align 4 @post: or si, si ; DS:SI->_pktRxBuf[n][n].destinAdr jz @discard ; make sure we don't use NULL-pointer sub si, 6 ; DS:SI -> _pktRxBuf[n].destinAdr ; ; push si ; push [si].firstCount ; call bpf_filter_match ; run the filter here some day? ; add sp, 4 ; cmp ax, 0 ; je @discard mov [si].secondCount, cx mov ax, newInOffset mov _rxInOfs, ax ; update _pktRxBuf input offset align 4 @discard:pop ds popf retf _pktRxEnd db 0 ; marker for end of r-mode code/data _TEXT ENDS END libpcap-1.8.1/msdos/common.dj0000644000026300017510000000315713003771737014230 0ustar mcrmcr# # Common defines for libpcap and 16/32-bit network drivers (djgpp) # .SUFFIXES: .exe .wlm .dxe .l .y .PHONY: check_gcclib default: check_gcclib all # # This value is normally not important. Used by 'dxe3gen' in # msdos/pm_drvr/makefile.dj to make "dynamically loaded modules". # But this is not finished. # #GCC_LIB = $(shell gcc -print-libgcc-file-name) GCC_LIB = . MAKEFILE = Makefile.dj # # DLX 2.91+ lib. Change path to suite. # Not used anymore. Uses DXE3 now. # # DLX_LIB = $(DJDIR)/contrib/dlx.291/libdlx.a # DLX_LINK = $(DJDIR)/bin/dlxgen.exe WATT32_ROOT = $(subst \,/,$(WATT_ROOT)) OBJ_DIR = djgpp.obj ifeq ($(wildcard $(GCC_LIB)),) check_gcclib: @echo libgcc.a not found. Set \"$(GCC_LIB)\" to \"/djgpp/lib/gcc/djgpp/4.X/libgcc.a\" endif # # Include 32-bit driver support # USE_32BIT_DRIVERS = 0 # # Use loadable driver modules instead of statically linking # all drivers. # USE_32BIT_MODULES = 0 # # Put interrupt sensitive code/data in locked sections # Do `make clean' in all affected directories after changing this. # USE_SECTION_LOCKING = 0 # # Set to 1 to use exception handler lib (only for me) # USE_EXCEPT = 0 CC = gcc.exe LD = ld.exe ASM = nasm.exe -fbin -dDEBUG YACC = bison.exe LEX = flex.exe CFLAGS = -g -O2 -Wall -I. -I$(WATT32_ROOT)/inc ifeq ($(USE_EXCEPT),1) CFLAGS += -DUSE_EXCEPT EXC_LIB = d:/prog/mw/except/lib/libexc.a endif ifeq ($(USE_SECTION_LOCKING),1) CFLAGS += -DUSE_SECTION_LOCKING endif ifeq ($(USE_32BIT_DRIVERS),1) CFLAGS += -DUSE_32BIT_DRIVERS endif %.o: %.c $(CC) -c $(CFLAGS) -o $@ $< @echo %.o: %.s $(CC) -c $(CFLAGS) -x assembler-with-cpp -o $@ $< @echo libpcap-1.8.1/msdos/bin2c.c0000644000026300017510000000157313003771737013562 0ustar mcrmcr#include #include #include #include static void Abort (const char *fmt,...) { va_list args; va_start (args, fmt); vfprintf (stderr, fmt, args); va_end (args); exit (1); } int main (int argc, char **argv) { FILE *inFile; FILE *outFile = stdout; time_t now = time (NULL); int ch, i; if (argc != 2) Abort ("Usage: %s bin-file [> result]", argv[0]); if ((inFile = fopen(argv[1],"rb")) == NULL) Abort ("Cannot open %s\n", argv[1]); fprintf (outFile, "/* data statements for file %s at %.24s */\n" "/* Generated by BIN2C, G. Vanem 1995 */\n", argv[1], ctime(&now)); i = 0; while ((ch = fgetc(inFile)) != EOF) { if (i++ % 12 == 0) fputs ("\n ", outFile); fprintf (outFile, "0x%02X,", ch); } fputc ('\n', outFile); fclose (inFile); return (0); } libpcap-1.8.1/msdos/pktdrvr.c0000644000026300017510000011326113003771737014257 0ustar mcrmcr/* * File.........: pktdrvr.c * * Responsible..: Gisle Vanem, giva@bgnett.no * * Created......: 26.Sept 1995 * * Description..: Packet-driver interface for 16/32-bit C : * Borland C/C++ 3.0+ small/large model * Watcom C/C++ 11+, DOS4GW flat model * Metaware HighC 3.1+ and PharLap 386|DosX * GNU C/C++ 2.7+ and djgpp 2.x extender * * References...: PC/TCP Packet driver Specification. rev 1.09 * FTP Software Inc. * */ #include #include #include #include #include "pcap-dos.h" #include "pcap-int.h" #include "msdos/pktdrvr.h" #if (DOSX) #define NUM_RX_BUF 32 /* # of buffers in Rx FIFO queue */ #else #define NUM_RX_BUF 10 #endif #define DIM(x) (sizeof((x)) / sizeof(x[0])) #define PUTS(s) do { \ if (!pktInfo.quiet) \ pktInfo.error ? \ printf ("%s: %s\n", s, pktInfo.error) : \ printf ("%s\n", pktInfo.error = s); \ } while (0) #if defined(__HIGHC__) extern UINT _mwenv; #elif defined(__DJGPP__) #include #include #include #include #include #elif defined(__WATCOMC__) #include #include extern char _Extender; #else extern void far PktReceiver (void); #endif #if (DOSX & (DJGPP|DOS4GW)) #include struct DPMI_regs { DWORD r_di; DWORD r_si; DWORD r_bp; DWORD reserved; DWORD r_bx; DWORD r_dx; DWORD r_cx; DWORD r_ax; WORD r_flags; WORD r_es, r_ds, r_fs, r_gs; WORD r_ip, r_cs, r_sp, r_ss; }; /* Data located in a real-mode segment. This becomes far at runtime */ typedef struct { /* must match data/code in pkt_rx1.s */ WORD _rxOutOfs; WORD _rxInOfs; DWORD _pktDrop; BYTE _pktTemp [20]; TX_ELEMENT _pktTxBuf[1]; RX_ELEMENT _pktRxBuf[NUM_RX_BUF]; WORD _dummy[2]; /* screenSeg,newInOffset */ BYTE _fanChars[4]; WORD _fanIndex; BYTE _PktReceiver[15]; /* starts on a paragraph (16byte) */ } PktRealStub; #include static BYTE real_stub_array [] = { #include "pkt_stub.inc" /* generated opcode array */ }; #define rxOutOfs offsetof (PktRealStub,_rxOutOfs) #define rxInOfs offsetof (PktRealStub,_rxInOfs) #define PktReceiver offsetof (PktRealStub,_PktReceiver [para_skip]) #define pktDrop offsetof (PktRealStub,_pktDrop) #define pktTemp offsetof (PktRealStub,_pktTemp) #define pktTxBuf offsetof (PktRealStub,_pktTxBuf) #define FIRST_RX_BUF offsetof (PktRealStub,_pktRxBuf [0]) #define LAST_RX_BUF offsetof (PktRealStub,_pktRxBuf [NUM_RX_BUF-1]) #else extern WORD rxOutOfs; /* offsets into pktRxBuf FIFO queue */ extern WORD rxInOfs; extern DWORD pktDrop; /* # packets dropped in PktReceiver() */ extern BYTE pktRxEnd; /* marks the end of r-mode code/data */ extern RX_ELEMENT pktRxBuf [NUM_RX_BUF]; /* PktDrvr Rx buffers */ extern TX_ELEMENT pktTxBuf; /* PktDrvr Tx buffer */ extern char pktTemp[20]; /* PktDrvr temp area */ #define FIRST_RX_BUF (WORD) &pktRxBuf [0] #define LAST_RX_BUF (WORD) &pktRxBuf [NUM_RX_BUF-1] #endif #ifdef __BORLANDC__ /* Use Borland's inline functions */ #define memcpy __memcpy__ #define memcmp __memcmp__ #define memset __memset__ #endif #if (DOSX & PHARLAP) extern void PktReceiver (void); /* in pkt_rx0.asm */ static int RealCopy (ULONG, ULONG, REALPTR*, FARPTR*, USHORT*); #undef FP_SEG #undef FP_OFF #define FP_OFF(x) ((WORD)(x)) #define FP_SEG(x) ((WORD)(realBase >> 16)) #define DOS_ADDR(s,o) (((DWORD)(s) << 16) + (WORD)(o)) #define r_ax eax #define r_bx ebx #define r_dx edx #define r_cx ecx #define r_si esi #define r_di edi #define r_ds ds #define r_es es LOCAL FARPTR protBase; LOCAL REALPTR realBase; LOCAL WORD realSeg; /* DOS para-address of allocated area */ LOCAL SWI_REGS reg; static WORD _far *rxOutOfsFp, *rxInOfsFp; #elif (DOSX & DJGPP) static _go32_dpmi_seginfo rm_mem; static __dpmi_regs reg; static DWORD realBase; static int para_skip = 0; #define DOS_ADDR(s,o) (((WORD)(s) << 4) + (o)) #define r_ax x.ax #define r_bx x.bx #define r_dx x.dx #define r_cx x.cx #define r_si x.si #define r_di x.di #define r_ds x.ds #define r_es x.es #elif (DOSX & DOS4GW) LOCAL struct DPMI_regs reg; LOCAL WORD rm_base_seg, rm_base_sel; LOCAL DWORD realBase; LOCAL int para_skip = 0; LOCAL DWORD dpmi_get_real_vector (int intr); LOCAL WORD dpmi_real_malloc (int size, WORD *selector); LOCAL void dpmi_real_free (WORD selector); #define DOS_ADDR(s,o) (((DWORD)(s) << 4) + (WORD)(o)) #else /* real-mode Borland etc. */ static struct { WORD r_ax, r_bx, r_cx, r_dx, r_bp; WORD r_si, r_di, r_ds, r_es, r_flags; } reg; #endif #ifdef __HIGHC__ #pragma Alias (pktDrop, "_pktDrop") #pragma Alias (pktRxBuf, "_pktRxBuf") #pragma Alias (pktTxBuf, "_pktTxBuf") #pragma Alias (pktTemp, "_pktTemp") #pragma Alias (rxOutOfs, "_rxOutOfs") #pragma Alias (rxInOfs, "_rxInOfs") #pragma Alias (pktRxEnd, "_pktRxEnd") #pragma Alias (PktReceiver,"_PktReceiver") #endif PUBLIC PKT_STAT pktStat; /* statistics for packets */ PUBLIC PKT_INFO pktInfo; /* packet-driver information */ PUBLIC PKT_RX_MODE receiveMode = PDRX_DIRECT; PUBLIC ETHER myAddress = { 0, 0, 0, 0, 0, 0 }; PUBLIC ETHER ethBroadcast = { 255,255,255,255,255,255 }; LOCAL struct { /* internal statistics */ DWORD tooSmall; /* size < ETH_MIN */ DWORD tooLarge; /* size > ETH_MAX */ DWORD badSync; /* count_1 != count_2 */ DWORD wrongHandle; /* upcall to wrong handle */ } intStat; /***************************************************************************/ PUBLIC const char *PktGetErrorStr (int errNum) { static const char *errStr[] = { "", "Invalid handle number", "No interfaces of specified class found", "No interfaces of specified type found", "No interfaces of specified number found", "Bad packet type specified", "Interface does not support multicast", "Packet driver cannot terminate", "Invalid receiver mode specified", "Insufficient memory space", "Type previously accessed, and not released", "Command out of range, or not implemented", "Cannot send packet (usually hardware error)", "Cannot change hardware address ( > 1 handle open)", "Hardware address has bad length or format", "Cannot reset interface (more than 1 handle open)", "Bad Check-sum", "Bad size", "Bad sync" , "Source hit" }; if (errNum < 0 || errNum >= DIM(errStr)) return ("Unknown driver error."); return (errStr [errNum]); } /**************************************************************************/ PUBLIC const char *PktGetClassName (WORD class) { switch (class) { case PD_ETHER: return ("DIX-Ether"); case PD_PRONET10: return ("ProNET-10"); case PD_IEEE8025: return ("IEEE 802.5"); case PD_OMNINET: return ("OmniNet"); case PD_APPLETALK: return ("AppleTalk"); case PD_SLIP: return ("SLIP"); case PD_STARTLAN: return ("StartLAN"); case PD_ARCNET: return ("ArcNet"); case PD_AX25: return ("AX.25"); case PD_KISS: return ("KISS"); case PD_IEEE8023_2: return ("IEEE 802.3 w/802.2 hdr"); case PD_FDDI8022: return ("FDDI w/802.2 hdr"); case PD_X25: return ("X.25"); case PD_LANstar: return ("LANstar"); case PD_PPP: return ("PPP"); default: return ("unknown"); } } /**************************************************************************/ PUBLIC char const *PktRXmodeStr (PKT_RX_MODE mode) { static const char *modeStr [] = { "Receiver turned off", "Receive only directly addressed packets", "Receive direct & broadcast packets", "Receive direct,broadcast and limited multicast packets", "Receive direct,broadcast and all multicast packets", "Receive all packets (promiscuouos mode)" }; if (mode > DIM(modeStr)) return ("??"); return (modeStr [mode-1]); } /**************************************************************************/ LOCAL __inline BOOL PktInterrupt (void) { BOOL okay; #if (DOSX & PHARLAP) _dx_real_int ((UINT)pktInfo.intr, ®); okay = ((reg.flags & 1) == 0); /* OK if carry clear */ #elif (DOSX & DJGPP) __dpmi_int ((int)pktInfo.intr, ®); okay = ((reg.x.flags & 1) == 0); #elif (DOSX & DOS4GW) union REGS r; struct SREGS s; memset (&r, 0, sizeof(r)); segread (&s); r.w.ax = 0x300; r.x.ebx = pktInfo.intr; r.w.cx = 0; s.es = FP_SEG (®); r.x.edi = FP_OFF (®); reg.r_flags = 0; reg.r_ss = reg.r_sp = 0; /* DPMI host provides stack */ int386x (0x31, &r, &r, &s); okay = (!r.w.cflag); #else reg.r_flags = 0; intr (pktInfo.intr, (struct REGPACK*)®); okay = ((reg.r_flags & 1) == 0); #endif if (okay) pktInfo.error = NULL; else pktInfo.error = PktGetErrorStr (reg.r_dx >> 8); return (okay); } /**************************************************************************/ /* * Search for packet driver at interrupt 60h through 80h. If ASCIIZ * string "PKT DRVR" found at offset 3 in the interrupt handler, return * interrupt number, else return zero in pktInfo.intr */ PUBLIC BOOL PktSearchDriver (void) { BYTE intr = 0x20; BOOL found = FALSE; while (!found && intr < 0xFF) { static char str[12]; /* 3 + strlen("PKT DRVR") */ static char pktStr[9] = "PKT DRVR"; /* ASCIIZ string at ofs 3 */ DWORD rp; /* in interrupt routine */ #if (DOSX & PHARLAP) _dx_rmiv_get (intr, &rp); ReadRealMem (&str, (REALPTR)rp, sizeof(str)); #elif (DOSX & DJGPP) __dpmi_raddr realAdr; __dpmi_get_real_mode_interrupt_vector (intr, &realAdr); rp = (realAdr.segment << 4) + realAdr.offset16; dosmemget (rp, sizeof(str), &str); #elif (DOSX & DOS4GW) rp = dpmi_get_real_vector (intr); memcpy (&str, (void*)rp, sizeof(str)); #else _fmemcpy (&str, getvect(intr), sizeof(str)); #endif found = memcmp (&str[3],&pktStr,sizeof(pktStr)) == 0; intr++; } pktInfo.intr = (found ? intr-1 : 0); return (found); } /**************************************************************************/ static BOOL PktSetAccess (void) { reg.r_ax = 0x0200 + pktInfo.class; reg.r_bx = 0xFFFF; reg.r_dx = 0; reg.r_cx = 0; #if (DOSX & PHARLAP) reg.ds = 0; reg.esi = 0; reg.es = RP_SEG (realBase); reg.edi = (WORD) &PktReceiver; #elif (DOSX & DJGPP) reg.x.ds = 0; reg.x.si = 0; reg.x.es = rm_mem.rm_segment; reg.x.di = PktReceiver; #elif (DOSX & DOS4GW) reg.r_ds = 0; reg.r_si = 0; reg.r_es = rm_base_seg; reg.r_di = PktReceiver; #else reg.r_ds = 0; reg.r_si = 0; reg.r_es = FP_SEG (&PktReceiver); reg.r_di = FP_OFF (&PktReceiver); #endif if (!PktInterrupt()) return (FALSE); pktInfo.handle = reg.r_ax; return (TRUE); } /**************************************************************************/ PUBLIC BOOL PktReleaseHandle (WORD handle) { reg.r_ax = 0x0300; reg.r_bx = handle; return PktInterrupt(); } /**************************************************************************/ PUBLIC BOOL PktTransmit (const void *eth, int len) { if (len > ETH_MTU) return (FALSE); reg.r_ax = 0x0400; /* Function 4, send pkt */ reg.r_cx = len; /* total size of frame */ #if (DOSX & DJGPP) dosmemput (eth, len, realBase+pktTxBuf); reg.x.ds = rm_mem.rm_segment; /* DOS data segment and */ reg.x.si = pktTxBuf; /* DOS offset to buffer */ #elif (DOSX & DOS4GW) memcpy ((void*)(realBase+pktTxBuf), eth, len); reg.r_ds = rm_base_seg; reg.r_si = pktTxBuf; #elif (DOSX & PHARLAP) memcpy (&pktTxBuf, eth, len); reg.r_ds = FP_SEG (&pktTxBuf); reg.r_si = FP_OFF (&pktTxBuf); #else reg.r_ds = FP_SEG (eth); reg.r_si = FP_OFF (eth); #endif return PktInterrupt(); } /**************************************************************************/ #if (DOSX & (DJGPP|DOS4GW)) LOCAL __inline BOOL CheckElement (RX_ELEMENT *rx) #else LOCAL __inline BOOL CheckElement (RX_ELEMENT _far *rx) #endif { WORD count_1, count_2; /* * We got an upcall to the same RMCB with wrong handle. * This can happen if we failed to release handle at program exit */ if (rx->handle != pktInfo.handle) { pktInfo.error = "Wrong handle"; intStat.wrongHandle++; PktReleaseHandle (rx->handle); return (FALSE); } count_1 = rx->firstCount; count_2 = rx->secondCount; if (count_1 != count_2) { pktInfo.error = "Bad sync"; intStat.badSync++; return (FALSE); } if (count_1 > ETH_MAX) { pktInfo.error = "Large esize"; intStat.tooLarge++; return (FALSE); } #if 0 if (count_1 < ETH_MIN) { pktInfo.error = "Small esize"; intStat.tooSmall++; return (FALSE); } #endif return (TRUE); } /**************************************************************************/ PUBLIC BOOL PktTerminHandle (WORD handle) { reg.r_ax = 0x0500; reg.r_bx = handle; return PktInterrupt(); } /**************************************************************************/ PUBLIC BOOL PktResetInterface (WORD handle) { reg.r_ax = 0x0700; reg.r_bx = handle; return PktInterrupt(); } /**************************************************************************/ PUBLIC BOOL PktSetReceiverMode (PKT_RX_MODE mode) { if (pktInfo.class == PD_SLIP || pktInfo.class == PD_PPP) return (TRUE); reg.r_ax = 0x1400; reg.r_bx = pktInfo.handle; reg.r_cx = (WORD)mode; if (!PktInterrupt()) return (FALSE); receiveMode = mode; return (TRUE); } /**************************************************************************/ PUBLIC BOOL PktGetReceiverMode (PKT_RX_MODE *mode) { reg.r_ax = 0x1500; reg.r_bx = pktInfo.handle; if (!PktInterrupt()) return (FALSE); *mode = reg.r_ax; return (TRUE); } /**************************************************************************/ static PKT_STAT initialStat; /* statistics at startup */ static BOOL resetStat = FALSE; /* statistics reset ? */ PUBLIC BOOL PktGetStatistics (WORD handle) { reg.r_ax = 0x1800; reg.r_bx = handle; if (!PktInterrupt()) return (FALSE); #if (DOSX & PHARLAP) ReadRealMem (&pktStat, DOS_ADDR(reg.ds,reg.esi), sizeof(pktStat)); #elif (DOSX & DJGPP) dosmemget (DOS_ADDR(reg.x.ds,reg.x.si), sizeof(pktStat), &pktStat); #elif (DOSX & DOS4GW) memcpy (&pktStat, (void*)DOS_ADDR(reg.r_ds,reg.r_si), sizeof(pktStat)); #else _fmemcpy (&pktStat, MK_FP(reg.r_ds,reg.r_si), sizeof(pktStat)); #endif return (TRUE); } /**************************************************************************/ PUBLIC BOOL PktSessStatistics (WORD handle) { if (!PktGetStatistics(pktInfo.handle)) return (FALSE); if (resetStat) { pktStat.inPackets -= initialStat.inPackets; pktStat.outPackets -= initialStat.outPackets; pktStat.inBytes -= initialStat.inBytes; pktStat.outBytes -= initialStat.outBytes; pktStat.inErrors -= initialStat.inErrors; pktStat.outErrors -= initialStat.outErrors; pktStat.outErrors -= initialStat.outErrors; pktStat.lost -= initialStat.lost; } return (TRUE); } /**************************************************************************/ PUBLIC BOOL PktResetStatistics (WORD handle) { if (!PktGetStatistics(pktInfo.handle)) return (FALSE); memcpy (&initialStat, &pktStat, sizeof(initialStat)); resetStat = TRUE; return (TRUE); } /**************************************************************************/ PUBLIC BOOL PktGetAddress (ETHER *addr) { reg.r_ax = 0x0600; reg.r_bx = pktInfo.handle; reg.r_cx = sizeof (*addr); #if (DOSX & DJGPP) reg.x.es = rm_mem.rm_segment; reg.x.di = pktTemp; #elif (DOSX & DOS4GW) reg.r_es = rm_base_seg; reg.r_di = pktTemp; #else reg.r_es = FP_SEG (&pktTemp); reg.r_di = FP_OFF (&pktTemp); /* ES:DI = address for result */ #endif if (!PktInterrupt()) return (FALSE); #if (DOSX & PHARLAP) ReadRealMem (addr, realBase + (WORD)&pktTemp, sizeof(*addr)); #elif (DOSX & DJGPP) dosmemget (realBase+pktTemp, sizeof(*addr), addr); #elif (DOSX & DOS4GW) memcpy (addr, (void*)(realBase+pktTemp), sizeof(*addr)); #else memcpy ((void*)addr, &pktTemp, sizeof(*addr)); #endif return (TRUE); } /**************************************************************************/ PUBLIC BOOL PktSetAddress (const ETHER *addr) { /* copy addr to real-mode scrath area */ #if (DOSX & PHARLAP) WriteRealMem (realBase + (WORD)&pktTemp, (void*)addr, sizeof(*addr)); #elif (DOSX & DJGPP) dosmemput (addr, sizeof(*addr), realBase+pktTemp); #elif (DOSX & DOS4GW) memcpy ((void*)(realBase+pktTemp), addr, sizeof(*addr)); #else memcpy (&pktTemp, (void*)addr, sizeof(*addr)); #endif reg.r_ax = 0x1900; reg.r_cx = sizeof (*addr); /* address length */ #if (DOSX & DJGPP) reg.x.es = rm_mem.rm_segment; /* DOS offset to param */ reg.x.di = pktTemp; /* DOS segment to param */ #elif (DOSX & DOS4GW) reg.r_es = rm_base_seg; reg.r_di = pktTemp; #else reg.r_es = FP_SEG (&pktTemp); reg.r_di = FP_OFF (&pktTemp); #endif return PktInterrupt(); } /**************************************************************************/ PUBLIC BOOL PktGetDriverInfo (void) { pktInfo.majVer = 0; pktInfo.minVer = 0; memset (&pktInfo.name, 0, sizeof(pktInfo.name)); reg.r_ax = 0x01FF; reg.r_bx = 0; if (!PktInterrupt()) return (FALSE); pktInfo.number = reg.r_cx & 0xFF; pktInfo.class = reg.r_cx >> 8; #if 0 pktInfo.minVer = reg.r_bx % 10; pktInfo.majVer = reg.r_bx / 10; #else pktInfo.majVer = reg.r_bx; // !! #endif pktInfo.funcs = reg.r_ax & 0xFF; pktInfo.type = reg.r_dx & 0xFF; #if (DOSX & PHARLAP) ReadRealMem (&pktInfo.name, DOS_ADDR(reg.ds,reg.esi), sizeof(pktInfo.name)); #elif (DOSX & DJGPP) dosmemget (DOS_ADDR(reg.x.ds,reg.x.si), sizeof(pktInfo.name), &pktInfo.name); #elif (DOSX & DOS4GW) memcpy (&pktInfo.name, (void*)DOS_ADDR(reg.r_ds,reg.r_si), sizeof(pktInfo.name)); #else _fmemcpy (&pktInfo.name, MK_FP(reg.r_ds,reg.r_si), sizeof(pktInfo.name)); #endif return (TRUE); } /**************************************************************************/ PUBLIC BOOL PktGetDriverParam (void) { reg.r_ax = 0x0A00; if (!PktInterrupt()) return (FALSE); #if (DOSX & PHARLAP) ReadRealMem (&pktInfo.majVer, DOS_ADDR(reg.es,reg.edi), PKT_PARAM_SIZE); #elif (DOSX & DJGPP) dosmemget (DOS_ADDR(reg.x.es,reg.x.di), PKT_PARAM_SIZE, &pktInfo.majVer); #elif (DOSX & DOS4GW) memcpy (&pktInfo.majVer, (void*)DOS_ADDR(reg.r_es,reg.r_di), PKT_PARAM_SIZE); #else _fmemcpy (&pktInfo.majVer, MK_FP(reg.r_es,reg.r_di), PKT_PARAM_SIZE); #endif return (TRUE); } /**************************************************************************/ #if (DOSX & PHARLAP) PUBLIC int PktReceive (BYTE *buf, int max) { WORD inOfs = *rxInOfsFp; WORD outOfs = *rxOutOfsFp; if (outOfs != inOfs) { RX_ELEMENT _far *head = (RX_ELEMENT _far*)(protBase+outOfs); int size, len = max; if (CheckElement(head)) { size = min (head->firstCount, sizeof(RX_ELEMENT)); len = min (size, max); _fmemcpy (buf, &head->destin, len); } else size = -1; outOfs += sizeof (RX_ELEMENT); if (outOfs > LAST_RX_BUF) outOfs = FIRST_RX_BUF; *rxOutOfsFp = outOfs; return (size); } return (0); } PUBLIC void PktQueueBusy (BOOL busy) { *rxOutOfsFp = busy ? (*rxInOfsFp + sizeof(RX_ELEMENT)) : *rxInOfsFp; if (*rxOutOfsFp > LAST_RX_BUF) *rxOutOfsFp = FIRST_RX_BUF; *(DWORD _far*)(protBase + (WORD)&pktDrop) = 0; } PUBLIC WORD PktBuffersUsed (void) { WORD inOfs = *rxInOfsFp; WORD outOfs = *rxOutOfsFp; if (inOfs >= outOfs) return (inOfs - outOfs) / sizeof(RX_ELEMENT); return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); } PUBLIC DWORD PktRxDropped (void) { return (*(DWORD _far*)(protBase + (WORD)&pktDrop)); } #elif (DOSX & DJGPP) PUBLIC int PktReceive (BYTE *buf, int max) { WORD ofs = _farpeekw (_dos_ds, realBase+rxOutOfs); if (ofs != _farpeekw (_dos_ds, realBase+rxInOfs)) { RX_ELEMENT head; int size, len = max; head.firstCount = _farpeekw (_dos_ds, realBase+ofs); head.secondCount = _farpeekw (_dos_ds, realBase+ofs+2); head.handle = _farpeekw (_dos_ds, realBase+ofs+4); if (CheckElement(&head)) { size = min (head.firstCount, sizeof(RX_ELEMENT)); len = min (size, max); dosmemget (realBase+ofs+6, len, buf); } else size = -1; ofs += sizeof (RX_ELEMENT); if (ofs > LAST_RX_BUF) _farpokew (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF); else _farpokew (_dos_ds, realBase+rxOutOfs, ofs); return (size); } return (0); } PUBLIC void PktQueueBusy (BOOL busy) { WORD ofs; disable(); ofs = _farpeekw (_dos_ds, realBase+rxInOfs); if (busy) ofs += sizeof (RX_ELEMENT); if (ofs > LAST_RX_BUF) _farpokew (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF); else _farpokew (_dos_ds, realBase+rxOutOfs, ofs); _farpokel (_dos_ds, realBase+pktDrop, 0UL); enable(); } PUBLIC WORD PktBuffersUsed (void) { WORD inOfs, outOfs; disable(); inOfs = _farpeekw (_dos_ds, realBase+rxInOfs); outOfs = _farpeekw (_dos_ds, realBase+rxOutOfs); enable(); if (inOfs >= outOfs) return (inOfs - outOfs) / sizeof(RX_ELEMENT); return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); } PUBLIC DWORD PktRxDropped (void) { return _farpeekl (_dos_ds, realBase+pktDrop); } #elif (DOSX & DOS4GW) PUBLIC int PktReceive (BYTE *buf, int max) { WORD ofs = *(WORD*) (realBase+rxOutOfs); if (ofs != *(WORD*) (realBase+rxInOfs)) { RX_ELEMENT head; int size, len = max; head.firstCount = *(WORD*) (realBase+ofs); head.secondCount = *(WORD*) (realBase+ofs+2); head.handle = *(WORD*) (realBase+ofs+4); if (CheckElement(&head)) { size = min (head.firstCount, sizeof(RX_ELEMENT)); len = min (size, max); memcpy (buf, (const void*)(realBase+ofs+6), len); } else size = -1; ofs += sizeof (RX_ELEMENT); if (ofs > LAST_RX_BUF) *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF; else *(WORD*) (realBase+rxOutOfs) = ofs; return (size); } return (0); } PUBLIC void PktQueueBusy (BOOL busy) { WORD ofs; _disable(); ofs = *(WORD*) (realBase+rxInOfs); if (busy) ofs += sizeof (RX_ELEMENT); if (ofs > LAST_RX_BUF) *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF; else *(WORD*) (realBase+rxOutOfs) = ofs; *(DWORD*) (realBase+pktDrop) = 0UL; _enable(); } PUBLIC WORD PktBuffersUsed (void) { WORD inOfs, outOfs; _disable(); inOfs = *(WORD*) (realBase+rxInOfs); outOfs = *(WORD*) (realBase+rxOutOfs); _enable(); if (inOfs >= outOfs) return (inOfs - outOfs) / sizeof(RX_ELEMENT); return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); } PUBLIC DWORD PktRxDropped (void) { return *(DWORD*) (realBase+pktDrop); } #else /* real-mode small/large model */ PUBLIC int PktReceive (BYTE *buf, int max) { if (rxOutOfs != rxInOfs) { RX_ELEMENT far *head = (RX_ELEMENT far*) MK_FP (_DS,rxOutOfs); int size, len = max; if (CheckElement(head)) { size = min (head->firstCount, sizeof(RX_ELEMENT)); len = min (size, max); _fmemcpy (buf, &head->destin, len); } else size = -1; rxOutOfs += sizeof (RX_ELEMENT); if (rxOutOfs > LAST_RX_BUF) rxOutOfs = FIRST_RX_BUF; return (size); } return (0); } PUBLIC void PktQueueBusy (BOOL busy) { rxOutOfs = busy ? (rxInOfs + sizeof(RX_ELEMENT)) : rxInOfs; if (rxOutOfs > LAST_RX_BUF) rxOutOfs = FIRST_RX_BUF; pktDrop = 0L; } PUBLIC WORD PktBuffersUsed (void) { WORD inOfs = rxInOfs; WORD outOfs = rxOutOfs; if (inOfs >= outOfs) return ((inOfs - outOfs) / sizeof(RX_ELEMENT)); return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); } PUBLIC DWORD PktRxDropped (void) { return (pktDrop); } #endif /**************************************************************************/ LOCAL __inline void PktFreeMem (void) { #if (DOSX & PHARLAP) if (realSeg) { _dx_real_free (realSeg); realSeg = 0; } #elif (DOSX & DJGPP) if (rm_mem.rm_segment) { unsigned ofs; /* clear the DOS-mem to prevent further upcalls */ for (ofs = 0; ofs < 16 * rm_mem.size / 4; ofs += 4) _farpokel (_dos_ds, realBase + ofs, 0); _go32_dpmi_free_dos_memory (&rm_mem); rm_mem.rm_segment = 0; } #elif (DOSX & DOS4GW) if (rm_base_sel) { dpmi_real_free (rm_base_sel); rm_base_sel = 0; } #endif } /**************************************************************************/ PUBLIC BOOL PktExitDriver (void) { if (pktInfo.handle) { if (!PktSetReceiverMode(PDRX_BROADCAST)) PUTS ("Error restoring receiver mode."); if (!PktReleaseHandle(pktInfo.handle)) PUTS ("Error releasing PKT-DRVR handle."); PktFreeMem(); pktInfo.handle = 0; } if (pcap_pkt_debug >= 1) printf ("Internal stats: too-small %lu, too-large %lu, bad-sync %lu, " "wrong-handle %lu\n", intStat.tooSmall, intStat.tooLarge, intStat.badSync, intStat.wrongHandle); return (TRUE); } #if (DOSX & (DJGPP|DOS4GW)) static void dump_pkt_stub (void) { int i; fprintf (stderr, "PktReceiver %lu, pkt_stub[PktReceiver] =\n", PktReceiver); for (i = 0; i < 15; i++) fprintf (stderr, "%02X, ", real_stub_array[i+PktReceiver]); fputs ("\n", stderr); } #endif /* * Front end initialization routine */ PUBLIC BOOL PktInitDriver (PKT_RX_MODE mode) { PKT_RX_MODE rxMode; BOOL writeInfo = (pcap_pkt_debug >= 3); pktInfo.quiet = (pcap_pkt_debug < 3); #if (DOSX & PHARLAP) && defined(__HIGHC__) if (_mwenv != 2) { fprintf (stderr, "Only Pharlap DOS extender supported.\n"); return (FALSE); } #endif #if (DOSX & PHARLAP) && defined(__WATCOMC__) if (_Extender != 1) { fprintf (stderr, "Only DOS4GW style extenders supported.\n"); return (FALSE); } #endif if (!PktSearchDriver()) { PUTS ("Packet driver not found."); PktFreeMem(); return (FALSE); } if (!PktGetDriverInfo()) { PUTS ("Error getting pkt-drvr information."); PktFreeMem(); return (FALSE); } #if (DOSX & PHARLAP) if (RealCopy((ULONG)&rxOutOfs, (ULONG)&pktRxEnd, &realBase, &protBase, (USHORT*)&realSeg)) { rxOutOfsFp = (WORD _far *) (protBase + (WORD) &rxOutOfs); rxInOfsFp = (WORD _far *) (protBase + (WORD) &rxInOfs); *rxOutOfsFp = FIRST_RX_BUF; *rxInOfsFp = FIRST_RX_BUF; } else { PUTS ("Cannot allocate real-mode stub."); return (FALSE); } #elif (DOSX & (DJGPP|DOS4GW)) if (sizeof(real_stub_array) > 0xFFFF) { fprintf (stderr, "`real_stub_array[]' too big.\n"); return (FALSE); } #if (DOSX & DJGPP) rm_mem.size = (sizeof(real_stub_array) + 15) / 16; if (_go32_dpmi_allocate_dos_memory(&rm_mem) || rm_mem.rm_offset != 0) { PUTS ("real-mode init failed."); return (FALSE); } realBase = (rm_mem.rm_segment << 4); dosmemput (&real_stub_array, sizeof(real_stub_array), realBase); _farpokel (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF); _farpokel (_dos_ds, realBase+rxInOfs, FIRST_RX_BUF); #elif (DOSX & DOS4GW) rm_base_seg = dpmi_real_malloc (sizeof(real_stub_array), &rm_base_sel); if (!rm_base_seg) { PUTS ("real-mode init failed."); return (FALSE); } realBase = (rm_base_seg << 4); memcpy ((void*)realBase, &real_stub_array, sizeof(real_stub_array)); *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF; *(WORD*) (realBase+rxInOfs) = FIRST_RX_BUF; #endif { int pushf = PktReceiver; while (real_stub_array[pushf++] != 0x9C && /* pushf */ real_stub_array[pushf] != 0xFA) /* cli */ { if (++para_skip > 16) { fprintf (stderr, "Something wrong with `pkt_stub.inc'.\n"); para_skip = 0; dump_pkt_stub(); return (FALSE); } } if (*(WORD*)(real_stub_array + offsetof(PktRealStub,_dummy)) != 0xB800) { fprintf (stderr, "`real_stub_array[]' is misaligned.\n"); return (FALSE); } } if (pcap_pkt_debug > 2) dump_pkt_stub(); #else rxOutOfs = FIRST_RX_BUF; rxInOfs = FIRST_RX_BUF; #endif if (!PktSetAccess()) { PUTS ("Error setting pkt-drvr access."); PktFreeMem(); return (FALSE); } if (!PktGetAddress(&myAddress)) { PUTS ("Error fetching adapter address."); PktFreeMem(); return (FALSE); } if (!PktSetReceiverMode(mode)) { PUTS ("Error setting receiver mode."); PktFreeMem(); return (FALSE); } if (!PktGetReceiverMode(&rxMode)) { PUTS ("Error getting receiver mode."); PktFreeMem(); return (FALSE); } if (writeInfo) printf ("Pkt-driver information:\n" " Version : %d.%d\n" " Name : %.15s\n" " Class : %u (%s)\n" " Type : %u\n" " Number : %u\n" " Funcs : %u\n" " Intr : %Xh\n" " Handle : %u\n" " Extended : %s\n" " Hi-perf : %s\n" " RX mode : %s\n" " Eth-addr : %02X:%02X:%02X:%02X:%02X:%02X\n", pktInfo.majVer, pktInfo.minVer, pktInfo.name, pktInfo.class, PktGetClassName(pktInfo.class), pktInfo.type, pktInfo.number, pktInfo.funcs, pktInfo.intr, pktInfo.handle, pktInfo.funcs == 2 || pktInfo.funcs == 6 ? "Yes" : "No", pktInfo.funcs == 5 || pktInfo.funcs == 6 ? "Yes" : "No", PktRXmodeStr(rxMode), myAddress[0], myAddress[1], myAddress[2], myAddress[3], myAddress[4], myAddress[5]); #if defined(DEBUG) && (DOSX & PHARLAP) if (writeInfo) { DWORD rAdr = realBase + (WORD)&PktReceiver; unsigned sel, ofs; printf ("\nReceiver at %04X:%04X\n", RP_SEG(rAdr), RP_OFF(rAdr)); printf ("Realbase = %04X:%04X\n", RP_SEG(realBase),RP_OFF(realBase)); sel = _FP_SEG (protBase); ofs = _FP_OFF (protBase); printf ("Protbase = %04X:%08X\n", sel,ofs); printf ("RealSeg = %04X\n", realSeg); sel = _FP_SEG (rxOutOfsFp); ofs = _FP_OFF (rxOutOfsFp); printf ("rxOutOfsFp = %04X:%08X\n", sel,ofs); sel = _FP_SEG (rxInOfsFp); ofs = _FP_OFF (rxInOfsFp); printf ("rxInOfsFp = %04X:%08X\n", sel,ofs); printf ("Ready: *rxOutOfsFp = %04X *rxInOfsFp = %04X\n", *rxOutOfsFp, *rxInOfsFp); PktQueueBusy (TRUE); printf ("Busy: *rxOutOfsFp = %04X *rxInOfsFp = %04X\n", *rxOutOfsFp, *rxInOfsFp); } #endif memset (&pktStat, 0, sizeof(pktStat)); /* clear statistics */ PktQueueBusy (TRUE); return (TRUE); } /* * DPMI functions only for Watcom + DOS4GW extenders */ #if (DOSX & DOS4GW) LOCAL DWORD dpmi_get_real_vector (int intr) { union REGS r; r.x.eax = 0x200; r.x.ebx = (DWORD) intr; int386 (0x31, &r, &r); return ((r.w.cx << 4) + r.w.dx); } LOCAL WORD dpmi_real_malloc (int size, WORD *selector) { union REGS r; r.x.eax = 0x0100; /* DPMI allocate DOS memory */ r.x.ebx = (size + 15) / 16; /* Number of paragraphs requested */ int386 (0x31, &r, &r); if (r.w.cflag & 1) return (0); *selector = r.w.dx; return (r.w.ax); /* Return segment address */ } LOCAL void dpmi_real_free (WORD selector) { union REGS r; r.x.eax = 0x101; /* DPMI free DOS memory */ r.x.ebx = selector; /* Selector to free */ int386 (0x31, &r, &r); } #endif #if defined(DOSX) && (DOSX & PHARLAP) /* * Description: * This routine allocates conventional memory for the specified block * of code (which must be within the first 64K of the protected mode * program segment) and copies the code to it. * * The caller should free up the conventional memory block when it * is done with the conventional memory. * * NOTE THIS ROUTINE REQUIRES 386|DOS-EXTENDER 3.0 OR LATER. * * Calling arguments: * start_offs start of real mode code in program segment * end_offs 1 byte past end of real mode code in program segment * real_basep returned; real mode ptr to use as a base for the * real mode code (eg, to get the real mode FAR * addr of a function foo(), take * real_basep + (ULONG) foo). * This pointer is constructed such that * offsets within the real mode segment are * the same as the link-time offsets in the * protected mode program segment * prot_basep returned; prot mode ptr to use as a base for getting * to the conventional memory, also constructed * so that adding the prot mode offset of a * function or variable to the base gets you a * ptr to the function or variable in the * conventional memory block. * rmem_adrp returned; real mode para addr of allocated * conventional memory block, to be used to free * up the conventional memory when done. DO NOT * USE THIS TO CONSTRUCT A REAL MODE PTR, USE * REAL_BASEP INSTEAD SO THAT OFFSETS WORK OUT * CORRECTLY. * * Returned values: * 0 if error * 1 if success */ int RealCopy (ULONG start_offs, ULONG end_offs, REALPTR *real_basep, FARPTR *prot_basep, USHORT *rmem_adrp) { ULONG rm_base; /* base real mode para addr for accessing */ /* allocated conventional memory */ UCHAR *source; /* source pointer for copy */ FARPTR destin; /* destination pointer for copy */ ULONG len; /* number of bytes to copy */ ULONG temp; USHORT stemp; /* First check for valid inputs */ if (start_offs >= end_offs || end_offs > 0x10000) return (FALSE); /* Round start_offs down to a paragraph (16-byte) boundary so we can set up * the real mode pointer easily. Round up end_offs to make sure we allocate * enough paragraphs */ start_offs &= ~15; end_offs = (15 + (end_offs << 4)) >> 4; /* Allocate the conventional memory for our real mode code. Remember to * round byte count UP to 16-byte paragraph size. We alloc it * above the DOS data buffer so both the DOS data buffer and the appl * conventional mem block can still be resized. * * First just try to alloc it; if we can't get it, shrink the appl mem * block down to the minimum, try to alloc the memory again, then grow the * appl mem block back to the maximum. (Don't try to shrink the DOS data * buffer to free conventional memory; it wouldn't be good for this routine * to have the possible side effect of making file I/O run slower.) */ len = ((end_offs - start_offs) + 15) >> 4; if (_dx_real_above(len, rmem_adrp, &stemp) != _DOSE_NONE) { if (_dx_cmem_usage(0, 0, &temp, &temp) != _DOSE_NONE) return (FALSE); if (_dx_real_above(len, rmem_adrp, &stemp) != _DOSE_NONE) *rmem_adrp = 0; if (_dx_cmem_usage(0, 1, &temp, &temp) != _DOSE_NONE) { if (*rmem_adrp != 0) _dx_real_free (*rmem_adrp); return (FALSE); } if (*rmem_adrp == 0) return (FALSE); } /* Construct real mode & protected mode pointers to access the allocated * memory. Note we know start_offs is aligned on a paragraph (16-byte) * boundary, because we rounded it down. * * We make the offsets come out rights by backing off the real mode selector * by start_offs. */ rm_base = ((ULONG) *rmem_adrp) - (start_offs >> 4); RP_SET (*real_basep, 0, rm_base); FP_SET (*prot_basep, rm_base << 4, SS_DOSMEM); /* Copy the real mode code/data to the allocated memory */ source = (UCHAR *) start_offs; destin = *prot_basep; FP_SET (destin, FP_OFF(*prot_basep) + start_offs, FP_SEL(*prot_basep)); len = end_offs - start_offs; WriteFarMem (destin, source, len); return (TRUE); } #endif /* DOSX && (DOSX & PHARLAP) */ libpcap-1.8.1/msdos/ndis2.c0000644000026300017510000005537513003771737013615 0ustar mcrmcr/* * Copyright (c) 1993,1994 * Texas A&M University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Texas A&M University * and its contributors. * 4. 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 BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Developers: * David K. Hess, Douglas Lee Schales, David R. Safford * * Heavily modified for Metaware HighC + GNU C 2.8+ * Gisle Vanem 1998 */ #include #include #include #include #include #include #include #include "pcap-dos.h" #include "pcap-int.h" #include "msdos/ndis2.h" #if defined(USE_NDIS2) /* * Packet buffer handling */ extern int FreePktBuf (PktBuf *buf); extern int EnquePktBuf (PktBuf *buf); extern PktBuf* AllocPktBuf (void); /* * Various defines */ #define MAX_NUM_DEBUG_STRINGS 90 #define DEBUG_STRING_LENGTH 80 #define STACK_POOL_SIZE 6 #define STACK_SIZE 256 #define MEDIA_FDDI 1 #define MEDIA_ETHERNET 2 #define MEDIA_TOKEN 3 static int startDebug = 0; static int stopDebug = 0; static DWORD droppedPackets = 0L; static WORD frameSize = 0; static WORD headerSize = 0; static int mediaType = 0; static char *lastErr = NULL; static BYTE debugStrings [MAX_NUM_DEBUG_STRINGS][DEBUG_STRING_LENGTH]; static BYTE *freeStacks [STACK_POOL_SIZE]; static int freeStackPtr = STACK_POOL_SIZE - 1; static ProtMan protManEntry = NULL; static WORD protManDS = 0; static volatile int xmitPending; static struct _PktBuf *txBufPending; static struct _CardHandle *handle; static struct _CommonChars common; static struct _ProtocolChars protChars; static struct _ProtDispatch lowerTable; static struct _FailingModules failingModules; static struct _BindingsList bindings; static struct { WORD err_num; char *err_text; } ndis_errlist[] = { { ERR_SUCCESS, "The function completed successfully.\n" }, { ERR_WAIT_FOR_RELEASE, "The ReceiveChain completed successfully but the protocol has\n" "retained control of the buffer.\n" }, { ERR_REQUEST_QUEUED, "The current request has been queued.\n" }, { ERR_FRAME_NOT_RECOGNIZED, "Frame not recognized.\n" }, { ERR_FRAME_REJECTED, "Frame was discarded.\n" }, { ERR_FORWARD_FRAME, "Protocol wishes to forward frame to another protocol.\n" }, { ERR_OUT_OF_RESOURCE, "Out of resource.\n" }, { ERR_INVALID_PARAMETER, "Invalid parameter.\n" }, { ERR_INVALID_FUNCTION, "Invalid function.\n" }, { ERR_NOT_SUPPORTED, "Not supported.\n" }, { ERR_HARDWARE_ERROR, "Hardware error.\n" }, { ERR_TRANSMIT_ERROR, "The packet was not transmitted due to an error.\n" }, { ERR_NO_SUCH_DESTINATION, "Token ring packet was not recognized when transmitted.\n" }, { ERR_BUFFER_TOO_SMALL, "Provided buffer was too small.\n" }, { ERR_ALREADY_STARTED, "Network drivers already started.\n" }, { ERR_INCOMPLETE_BINDING, "Protocol driver could not complete its bindings.\n" }, { ERR_DRIVER_NOT_INITIALIZED, "MAC did not initialize properly.\n" }, { ERR_HARDWARE_NOT_FOUND, "Hardware not found.\n" }, { ERR_HARDWARE_FAILURE, "Hardware failure.\n" }, { ERR_CONFIGURATION_FAILURE, "Configuration failure.\n" }, { ERR_INTERRUPT_CONFLICT, "Interrupt conflict.\n" }, { ERR_INCOMPATIBLE_MAC, "The MAC is not compatible with the protocol.\n" }, { ERR_INITIALIZATION_FAILED, "Initialization failed.\n" }, { ERR_NO_BINDING, "Binding did not occur.\n" }, { ERR_NETWORK_MAY_NOT_BE_CONNECTED, "The network may not be connected to the adapter.\n" }, { ERR_INCOMPATIBLE_OS_VERSION, "The version of the operating system is incompatible with the protocol.\n" }, { ERR_ALREADY_REGISTERED, "The protocol is already registered.\n" }, { ERR_PATH_NOT_FOUND, "PROTMAN.EXE could not be found.\n" }, { ERR_INSUFFICIENT_MEMORY, "Insufficient memory.\n" }, { ERR_INFO_NOT_FOUND, "Protocol Mananger info structure is lost or corrupted.\n" }, { ERR_GENERAL_FAILURE, "General failure.\n" } }; /* * Some handy macros */ #define PERROR(str) printf("%s (%d): %s\n", __FILE__,__LINE__,str) #define DEBUG_RING() (debugStrings[stopDebug+1 == MAX_NUM_DEBUG_STRINGS ? \ stopDebug = 0 : ++stopDebug]) /* * needs rewrite for DOSX */ #define MAC_DISPATCH(hnd) ((struct _MacUpperDispatch*)(hnd)->common->upperDispatchTable) #define MAC_STATUS(hnd) ((struct _MacStatusTable*) (hnd)->common->serviceStatus) #define MAC_CHAR(hnd) ((struct _MacChars*) (hnd)->common->serviceChars) #ifdef NDIS_DEBUG #define DEBUG0(str) printf (str) #define DEBUG1(fmt,a) printf (fmt,a) #define DEBUG2(fmt,a,b) printf (fmt,a,b) #define TRACE0(str) sprintf (DEBUG_RING(),str) #define TRACE1(fmt,a) sprintf (DEBUG_RING(),fmt,a) #else #define DEBUG0(str) ((void)0) #define DEBUG1(fmt,a) ((void)0) #define DEBUG2(fmt,a,b) ((void)0) #define TRACE0(str) ((void)0) #define TRACE1(fmt,a) ((void)0) #endif /* * This routine is called from both threads */ void NdisFreeStack (BYTE *aStack) { GUARD(); if (freeStackPtr == STACK_POOL_SIZE - 1) PERROR ("tried to free too many stacks"); freeStacks[++freeStackPtr] = aStack; if (freeStackPtr == 0) TRACE0 ("freeStackPtr went positive\n"); UNGUARD(); } /* * This routine is called from callbacks to allocate local data */ BYTE *NdisAllocStack (void) { BYTE *stack; GUARD(); if (freeStackPtr < 0) { /* Ran out of stack buffers. Return NULL which will start * dropping packets */ TRACE0 ("freeStackPtr went negative\n"); stack = 0; } else stack = freeStacks[freeStackPtr--]; UNGUARD(); return (stack); } CALLBACK (NdisSystemRequest (DWORD param1, DWORD param2, WORD param3, WORD opcode, WORD targetDS)) { static int bindEntry = 0; struct _CommonChars *macCommon; volatile WORD result; switch (opcode) { case REQ_INITIATE_BIND: macCommon = (struct _CommonChars*) param2; if (macCommon == NULL) { printf ("There is an NDIS misconfiguration.\n"); result = ERR_GENERAL_FAILURE; break; } DEBUG2 ("module name %s\n" "module type %s\n", macCommon->moduleName, ((MacChars*) macCommon->serviceChars)->macName); /* Binding to the MAC */ result = macCommon->systemRequest ((DWORD)&common, (DWORD)&macCommon, 0, REQ_BIND, macCommon->moduleDS); if (!strcmp(bindings.moduleName[bindEntry], handle->moduleName)) handle->common = macCommon; else PERROR ("unknown module"); ++bindEntry; break; case REQ_INITIATE_UNBIND: macCommon = (struct _CommonChars*) param2; result = macCommon->systemRequest ((DWORD)&common, 0, 0, REQ_UNBIND, macCommon->moduleDS); break; default: result = ERR_GENERAL_FAILURE; break; } ARGSUSED (param1); ARGSUSED (param3); ARGSUSED (targetDS); return (result); } CALLBACK (NdisRequestConfirm (WORD protId, WORD macId, WORD reqHandle, WORD status, WORD request, WORD protDS)) { ARGSUSED (protId); ARGSUSED (macId); ARGSUSED (reqHandle); ARGSUSED (status); ARGSUSED (request); ARGSUSED (protDS); return (ERR_SUCCESS); } CALLBACK (NdisTransmitConfirm (WORD protId, WORD macId, WORD reqHandle, WORD status, WORD protDS)) { xmitPending--; FreePktBuf (txBufPending); /* Add passed ECB back to the free list */ ARGSUSED (reqHandle); ARGSUSED (status); ARGSUSED (protDS); return (ERR_SUCCESS); } /* * The primary function for receiving packets */ CALLBACK (NdisReceiveLookahead (WORD macId, WORD frameSize, WORD bytesAvail, BYTE *buffer, BYTE *indicate, WORD protDS)) { int result; PktBuf *pktBuf; WORD bytesCopied; struct _TDBufDescr tDBufDescr; #if 0 TRACE1 ("lookahead length = %d, ", bytesAvail); TRACE1 ("ecb = %08lX, ", *ecb); TRACE1 ("count = %08lX\n", count); TRACE1 ("offset = %08lX, ", offset); TRACE1 ("timesAllowed = %d, ", timesAllowed); TRACE1 ("packet size = %d\n", look->dataLookAheadLen); #endif /* Allocate a buffer for the packet */ if ((pktBuf = AllocPktBuf()) == NULL) { droppedPackets++; return (ERR_FRAME_REJECTED); } /* * Now kludge things. Note we will have to undo this later. This will * make the packet contiguous after the MLID has done the requested copy. */ tDBufDescr.tDDataCount = 1; tDBufDescr.tDBufDescrRec[0].tDPtrType = NDIS_PTR_PHYSICAL; tDBufDescr.tDBufDescrRec[0].tDDataPtr = pktBuf->buffer; tDBufDescr.tDBufDescrRec[0].tDDataLen = pktBuf->length; tDBufDescr.tDBufDescrRec[0].dummy = 0; result = MAC_DISPATCH(handle)->transferData (&bytesCopied, 0, &tDBufDescr, handle->common->moduleDS); pktBuf->packetLength = bytesCopied; if (result == ERR_SUCCESS) EnquePktBuf(pktBuf); else FreePktBuf (pktBuf); ARGSUSED (frameSize); ARGSUSED (bytesAvail); ARGSUSED (indicate); ARGSUSED (protDS); return (ERR_SUCCESS); } CALLBACK (NdisIndicationComplete (WORD macId, WORD protDS)) { ARGSUSED (macId); ARGSUSED (protDS); /* We don't give a hoot about these. Just return */ return (ERR_SUCCESS); } /* * This is the OTHER way we may receive packets */ CALLBACK (NdisReceiveChain (WORD macId, WORD frameSize, WORD reqHandle, struct _RxBufDescr *rxBufDescr, BYTE *indicate, WORD protDS)) { struct _PktBuf *pktBuf; int i; /* * For now we copy the entire packet over to a PktBuf structure. This may be * a performance hit but this routine probably isn't called very much, and * it is a lot of work to do it otherwise. Also if it is a filter protocol * packet we could end up sucking up MAC buffes. */ if ((pktBuf = AllocPktBuf()) == NULL) { droppedPackets++; return (ERR_FRAME_REJECTED); } pktBuf->packetLength = 0; /* Copy the packet to the buffer */ for (i = 0; i < rxBufDescr->rxDataCount; ++i) { struct _RxBufDescrRec *rxDescr = &rxBufDescr->rxBufDescrRec[i]; memcpy (pktBuf->buffer + pktBuf->packetLength, rxDescr->rxDataPtr, rxDescr->rxDataLen); pktBuf->packetLength += rxDescr->rxDataLen; } EnquePktBuf (pktBuf); ARGSUSED (frameSize); ARGSUSED (reqHandle); ARGSUSED (indicate); ARGSUSED (protDS); /* This frees up the buffer for the MAC to use */ return (ERR_SUCCESS); } CALLBACK (NdisStatusProc (WORD macId, WORD param1, BYTE *indicate, WORD opcode, WORD protDS)) { switch (opcode) { case STATUS_RING_STATUS: break; case STATUS_ADAPTER_CHECK: break; case STATUS_START_RESET: break; case STATUS_INTERRUPT: break; case STATUS_END_RESET: break; default: break; } ARGSUSED (macId); ARGSUSED (param1); ARGSUSED (indicate); ARGSUSED (opcode); ARGSUSED (protDS); /* We don't need to do anything about this stuff yet */ return (ERR_SUCCESS); } /* * Tell the NDIS driver to start the delivery of the packet */ int NdisSendPacket (struct _PktBuf *pktBuf, int macId) { struct _TxBufDescr txBufDescr; int result; xmitPending++; txBufPending = pktBuf; /* we only have 1 pending Tx at a time */ txBufDescr.txImmedLen = 0; txBufDescr.txImmedPtr = NULL; txBufDescr.txDataCount = 1; txBufDescr.txBufDescrRec[0].txPtrType = NDIS_PTR_PHYSICAL; txBufDescr.txBufDescrRec[0].dummy = 0; txBufDescr.txBufDescrRec[0].txDataLen = pktBuf->packetLength; txBufDescr.txBufDescrRec[0].txDataPtr = pktBuf->buffer; result = MAC_DISPATCH(handle)->transmitChain (common.moduleId, pktBuf->handle, &txBufDescr, handle->common->moduleDS); switch (result) { case ERR_OUT_OF_RESOURCE: /* Note that this should not happen but if it does there is not * much we can do about it */ printf ("ERROR: transmit queue overflowed\n"); return (0); case ERR_SUCCESS: /* Everything was hunky dory and synchronous. Free up the * packet buffer */ xmitPending--; FreePktBuf (pktBuf); return (1); case ERR_REQUEST_QUEUED: /* Everything was hunky dory and asynchronous. Do nothing */ return (1); default: printf ("Tx fail, code = %04X\n", result); return (0); } } static int ndis_nerr = sizeof(ndis_errlist) / sizeof(ndis_errlist[0]); static char *Ndis_strerror (WORD errorCode) { static char buf[30]; int i; for (i = 0; i < ndis_nerr; i++) if (errorCode == ndis_errlist[i].err_num) return (ndis_errlist[i].err_text); sprintf (buf,"unknown error %d",errorCode); return (buf); } char *NdisLastError (void) { char *errStr = lastErr; lastErr = NULL; return (errStr); } int NdisOpen (void) { struct _ReqBlock reqBlock; int result; int ndisFd = open (NDIS_PATH, O_RDONLY); if (ndisFd < 0) { printf ("Could not open NDIS Protocol Manager device.\n"); return (0); } memset (&reqBlock, 0, sizeof(ReqBlock)); reqBlock.opcode = PM_GET_PROTOCOL_MANAGER_LINKAGE; result = NdisGetLinkage (ndisFd, (char*)&reqBlock, sizeof(ReqBlock)); if (result != 0) { printf ("Could not get Protocol Manager linkage.\n"); close (ndisFd); return (0); } close (ndisFd); protManEntry = (ProtMan) reqBlock.pointer1; protManDS = reqBlock.word1; DEBUG2 ("Entry Point = %04X:%04X\n", FP_SEG(protManEntry),FP_OFF(protManEntry)); DEBUG1 ("ProtMan DS = %04X\n", protManDS); return (1); } int NdisRegisterAndBind (int promis) { struct _ReqBlock reqBlock; WORD result; memset (&common,0,sizeof(common)); common.tableSize = sizeof (common); common.majorNdisVersion = 2; common.minorNdisVersion = 0; common.majorModuleVersion = 2; common.minorModuleVersion = 0; /* Indicates binding from below and dynamically loaded */ common.moduleFlags = 0x00000006L; strcpy (common.moduleName, "PCAP"); common.protocolLevelUpper = 0xFF; common.protocolLevelLower = 1; common.interfaceLower = 1; #ifdef __DJGPP__ common.moduleDS = _dos_ds; /* the callback data segment */ #else common.moduleDS = _DS; #endif common.systemRequest = (SystemRequest) systemRequestGlue; common.serviceChars = (BYTE*) &protChars; common.serviceStatus = NULL; common.upperDispatchTable = NULL; common.lowerDispatchTable = (BYTE*) &lowerTable; protChars.length = sizeof (protChars); protChars.name[0] = 0; protChars.type = 0; lowerTable.backPointer = &common; lowerTable.requestConfirm = requestConfirmGlue; lowerTable.transmitConfirm = transmitConfirmGlue; lowerTable.receiveLookahead = receiveLookaheadGlue; lowerTable.indicationComplete = indicationCompleteGlue; lowerTable.receiveChain = receiveChainGlue; lowerTable.status = statusGlue; lowerTable.flags = 3; if (promis) lowerTable.flags |= 4; /* promiscous mode (receive everything) */ bindings.numBindings = 1; strcpy (bindings.moduleName[0], handle->moduleName); /* Register ourselves with NDIS */ reqBlock.opcode = PM_REGISTER_MODULE; reqBlock.pointer1 = (BYTE FAR*) &common; reqBlock.pointer2 = (BYTE FAR*) &bindings; result = (*protManEntry) (&reqBlock, protManDS); if (result) { printf ("Protman registering failed: %s\n", Ndis_strerror(result)); return (0); } /* Start the binding process */ reqBlock.opcode = PM_BIND_AND_START; reqBlock.pointer1 = (BYTE FAR*) &failingModules; result = (*protManEntry) (&reqBlock, protManDS); if (result) { printf ("Start binding failed: %s\n", Ndis_strerror(result)); return (0); } return (1); } static int CheckMacFeatures (CardHandle *card) { DWORD serviceFlags; BYTE _far *mediaString; BYTE _far *mac_addr; DEBUG2 ("checking card features\n" "common table address = %08lX, macId = %d\n", card->common, card->common->moduleId); serviceFlags = MAC_CHAR (handle)->serviceFlags; if ((serviceFlags & SF_PROMISCUOUS) == 0) { printf ("The MAC %s does not support promiscuous mode.\n", card->moduleName); return (0); } mediaString = MAC_CHAR (handle)->macName; DEBUG1 ("media type = %s\n",mediaString); /* Get the media type. And set the header size */ if (!strncmp(mediaString,"802.3",5) || !strncmp(mediaString,"DIX",3) || !strncmp(mediaString,"DIX+802.3",9)) headerSize = sizeof (EthernetIIHeader); else if (!strncmp(mediaString,"FDDI",4)) headerSize = sizeof (FddiHeader) + sizeof (Ieee802Dot2SnapHeader); else { printf ("Unsupported MAC type: `%s'\n", mediaString); return (0); } frameSize = MAC_CHAR (handle)->maxFrameSize; mac_addr = MAC_CHAR (handle)->currentAddress; printf ("Hardware address: %02X:%02X:%02X:%02X:%02X:%02X\n", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); return (1); } static int NdisStartMac (CardHandle *card) { WORD result; /* Set the lookahead length */ result = MAC_DISPATCH(handle)->request (common.moduleId, 0, headerSize, 0, REQ_SET_LOOKAHEAD, card->common->moduleDS); /* We assume that if we got INVALID PARAMETER then either this * is not supported or will work anyway. NE2000 does this. */ if (result != ERR_SUCCESS && result != ERR_INVALID_PARAMETER) { DEBUG1 ("Set lookahead failed: %s\n", Ndis_strerror(result)); return (0); } /* Set the packet filter. Note that for some medias and drivers we * must specify all three flags or the card(s) will not operate correctly. */ result = MAC_DISPATCH(handle)->request (common.moduleId, 0, /* all packets */ FILTER_PROMISCUOUS | /* packets to us */ FILTER_DIRECTED | /* broadcasts */ FILTER_BROADCAST, 0, REQ_SET_PACKET_FILTER, card->common->moduleDS); if (result != ERR_SUCCESS) { DEBUG1 ("Set packet filter failed: %s\n", Ndis_strerror(result)); return (0); } /* If OPEN/CLOSE supported then open the adapter */ if (MAC_CHAR(handle)->serviceFlags & SF_OPEN_CLOSE) { result = MAC_DISPATCH(handle)->request (common.moduleId, 0, 0, NULL, REQ_OPEN_ADAPTER, card->common->moduleDS); if (result != ERR_SUCCESS) { DEBUG1 ("Opening the MAC failed: %s\n", Ndis_strerror(result)); return (0); } } return (1); } void NdisShutdown (void) { struct _ReqBlock reqBlock; int result, i; if (!handle) return; /* If the adapters support open and are open then close them */ if ((MAC_CHAR(handle)->serviceFlags & SF_OPEN_CLOSE) && (MAC_STATUS(handle)->macStatus & MAC_OPEN)) { result = MAC_DISPATCH(handle)->request (common.moduleId, 0, 0, 0, REQ_CLOSE_ADAPTER, handle->common->moduleDS); if (result != ERR_SUCCESS) { printf ("Closing the MAC failed: %s\n", Ndis_strerror(result)); return; } } /* Tell the Protocol Manager to unbind and stop */ reqBlock.opcode = PM_UNBIND_AND_STOP; reqBlock.pointer1 = (BYTE FAR*) &failingModules; reqBlock.pointer2 = NULL; result = (*protManEntry) (&reqBlock, protManDS); if (result) printf ("Unbind failed: %s\n", Ndis_strerror(result)); for (i = 0; i < STACK_POOL_SIZE; ++i) free (freeStacks[i] - STACK_SIZE); handle = NULL; } int NdisInit (int promis) { int i, result; /* Allocate the real mode stacks used for NDIS callbacks */ for (i = 0; i < STACK_POOL_SIZE; ++i) { freeStacks[i] = malloc (STACK_SIZE); if (!freeStacks[i]) return (0); freeStacks[i] += STACK_SIZE; } if (!NdisOpen()) return (0); if (!NdisRegisterAndBind(promis)) return (0); DEBUG1 ("My module id: %d\n", common.moduleId); DEBUG1 ("Handle id; %d\n", handle->common->moduleId); DEBUG1 ("MAC card: %-16s - ", handle->moduleName); atexit (NdisShutdown); if (!CheckMacFeatures(&handle)) return (0); switch (mediaType) { case MEDIA_FDDI: DEBUG0 ("Media type: FDDI"); break; case MEDIA_ETHERNET: DEBUG0 ("Media type: ETHERNET"); break; default: DEBUG0 ("Unsupported media.\n"); return (0); } DEBUG1 (" - Frame size: %d\n", frameSize); if (!NdisStartMac(&handle)) return (0); return (1); } #endif /* USE_NDIS2 */ libpcap-1.8.1/msdos/pkt_rx1.s0000644000026300017510000001173713003771737014200 0ustar mcrmcr; ; This file requires NASM 0.97+ to assemble ; ; Currently used only for djgpp + DOS4GW targets ; ; these sizes MUST be equal to the sizes in PKTDRVR.H ; %define ETH_MTU 1500 ; max data size on Ethernet %define ETH_MIN 60 ; min/max total frame size %define ETH_MAX (ETH_MTU+2*6+2) ; =1514 %define NUM_RX_BUF 32 ; # of RX element buffers %define RX_SIZE (ETH_MAX+6) ; sizeof(RX_ELEMENT) = 1514+6 %idefine offset struc RX_ELEMENT .firstCount resw 1 ; # of bytes on 1st call .secondCount resw 1 ; # of bytes on 2nd call .handle resw 1 ; handle for upcall ; .timeStamp resw 4 ; 64-bit RDTSC value .destinAdr resb 6 ; packet destination address .sourceAdr resb 6 ; packet source address .protocol resw 1 ; packet protocol number .rxBuffer resb ETH_MTU ; RX buffer endstruc ;------------------------------------------- [org 0] ; assemble to .bin file _rxOutOfs dw offset _pktRxBuf ; ring buffer offsets _rxInOfs dw offset _pktRxBuf ; into _pktRxBuf _pktDrop dw 0,0 ; packet drop counter _pktTemp resb 20 ; temp work area _pktTxBuf resb (ETH_MAX) ; TX buffer _pktRxBuf resb (RX_SIZE*NUM_RX_BUF) ; RX structures LAST_OFS equ $ screenSeg dw 0B800h newInOffset dw 0 fanChars db '-\|/' fanIndex dw 0 %macro SHOW_RX 0 push es push bx mov bx, [screenSeg] mov es, bx ;; r-mode segment of colour screen mov di, 158 ;; upper right corner - 1 mov bx, [fanIndex] mov al, [fanChars+bx] ;; get write char mov ah, 15 ;; and white colour cld ;; Needed? stosw ;; write to screen at ES:EDI inc word [fanIndex] ;; update next index and word [fanIndex], 3 pop bx pop es %endmacro ;PutTimeStamp ; rdtsc ; mov [si].timeStamp, eax ; mov [si+4].timeStamp, edx ; ret ;------------------------------------------------------------------------ ; ; This routine gets called by the packet driver twice: ; 1st time (AX=0) it requests an address where to put the packet ; ; 2nd time (AX=1) the packet has been copied to this location (DS:SI) ; BX has client handle (stored in RX_ELEMENT.handle). ; CX has # of bytes in packet on both call. They should be equal. ; A test for equality is done by putting CX in _pktRxBuf [n].firstCount ; and _pktRxBuf[n].secondCount, and CL on first call in ; _pktRxBuf[n].rxBuffer[CX]. These values are checked in "PktReceive" ; (PKTDRVR.C) ; ;--------------------------------------------------------------------- _PktReceiver: pushf cli ; no distraction wanted ! push ds push bx mov bx, cs mov ds, bx mov es, bx ; ES = DS = CS or seg _DATA pop bx ; restore handle cmp ax, 0 ; first call? (AX=0) jne @post ; AX=1: second call, do post process %ifdef DEBUG SHOW_RX ; show that a packet is received %endif cmp cx, ETH_MAX ; size OK ? ja @skip ; no, too big mov ax, [_rxInOfs] add ax, RX_SIZE cmp ax, LAST_OFS jb @noWrap mov ax, offset _pktRxBuf @noWrap: cmp ax, [_rxOutOfs] je @dump mov di, [_rxInOfs] ; ES:DI -> _pktRxBuf[n] mov [newInOffset], ax mov [di], cx ; remember firstCount. mov [di+4], bx ; remember handle. add di, 6 ; ES:DI -> _pktRxBuf[n].destinAdr pop ds popf retf ; far return to driver with ES:DI @dump: add word [_pktDrop+0], 1 ; discard the packet on 1st call adc word [_pktDrop+2], 0 ; increment packets lost @skip: xor di, di ; return ES:DI = NIL pointer xor ax, ax mov es, ax pop ds popf retf @post: or si, si ; DS:SI->_pktRxBuf[n][n].destinAdr jz @discard ; make sure we don't use NULL-pointer ; ; push si ; call bpf_filter_match ; run the filter here some day ; pop si ; cmp ax, 0 ; je @discard mov [si-6+2], cx ; store _pktRxBuf[n].secondCount mov ax, [newInOffset] mov [_rxInOfs], ax ; update _pktRxBuf input offset ; call PutTimeStamp @discard: pop ds popf retf _pktRxEnd db 0 ; marker for end of r-mode code/data END libpcap-1.8.1/msdos/ndis2.h0000644000026300017510000004172213003771737013611 0ustar mcrmcr/* * Copyright (c) 1993,1994 * Texas A&M University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Texas A&M University * and its contributors. * 4. 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 BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Developers: * David K. Hess, Douglas Lee Schales, David R. Safford * * Heavily modified for Metaware HighC + GNU C 2.8+ * Gisle Vanem 1998 */ #ifndef __PCAP_NDIS_H #define __PCAP_NDIS_H #if defined (__HIGHC__) #define pascal _CC(_CALLEE_POPS_STACK & ~_REVERSE_PARMS) /* calling convention */ #define CALLBACK(foo) pascal WORD foo #define PAS_PTR(x,arg) typedef FAR WORD pascal (*x) arg #define GUARD() _inline (0x9C,0xFA) /* pushfd, cli */ #define UNGUARD() _inline (0x9D) /* popfd */ #define FAR _far #elif defined(__GNUC__) #define CALLBACK(foo) WORD foo __attribute__((stdcall)) #define PAS_PTR(x,arg) typedef WORD (*x) arg __attribute__((stdcall)) #define GUARD() __asm__ __volatile__ ("pushfd; cli") #define UNGUARD() __asm__ __volatile__ ("popfd") #define FAR #elif defined (__TURBOC__) #define CALLBACK(foo) WORD pascal foo #define PAS_PTR(x,arg) typedef WORD pascal (_far *x) arg #define GUARD() _asm { pushf; cli } #define UNGUARD() _asm { popf } #define FAR _far #elif defined (__WATCOMC__) #define CALLBACK(foo) WORD pascal foo #define PAS_PTR(x,arg) typedef WORD pascal (_far *x) arg #define GUARD() _disable() #define UNGUARD() _enable() #define FAR _far #else #error Unsupported compiler #endif /* * Forwards */ struct _ReqBlock; struct _TxBufDescr; struct _TDBufDescr; /* * Protocol Manager API */ PAS_PTR (ProtMan, (struct _ReqBlock FAR*, WORD)); /* * System request */ PAS_PTR (SystemRequest, (DWORD, DWORD, WORD, WORD, WORD)); /* * MAC API */ PAS_PTR (TransmitChain, (WORD, WORD, struct _TxBufDescr FAR*, WORD)); PAS_PTR (TransferData, (WORD*,WORD, struct _TDBufDescr FAR*, WORD)); PAS_PTR (Request, (WORD, WORD, WORD, DWORD, WORD, WORD)); PAS_PTR (ReceiveRelease,(WORD, WORD)); PAS_PTR (IndicationOn, (WORD)); PAS_PTR (IndicationOff, (WORD)); typedef enum { HARDWARE_NOT_INSTALLED = 0, HARDWARE_FAILED_DIAG = 1, HARDWARE_FAILED_CONFIG = 2, HARDWARE_HARD_FAULT = 3, HARDWARE_SOFT_FAULT = 4, HARDWARE_OK = 7, HARDWARE_MASK = 0x0007, MAC_BOUND = 0x0008, MAC_OPEN = 0x0010, DIAG_IN_PROGRESS = 0x0020 } NdisMacStatus; typedef enum { STATUS_RING_STATUS = 1, STATUS_ADAPTER_CHECK = 2, STATUS_START_RESET = 3, STATUS_INTERRUPT = 4, STATUS_END_RESET = 5 } NdisStatus; typedef enum { FILTER_DIRECTED = 1, FILTER_BROADCAST = 2, FILTER_PROMISCUOUS = 4, FILTER_SOURCE_ROUTE = 8 } NdisPacketFilter; typedef enum { REQ_INITIATE_DIAGNOSTICS = 1, REQ_READ_ERROR_LOG = 2, REQ_SET_STATION_ADDRESS = 3, REQ_OPEN_ADAPTER = 4, REQ_CLOSE_ADAPTER = 5, REQ_RESET_MAC = 6, REQ_SET_PACKET_FILTER = 7, REQ_ADD_MULTICAST_ADDRESS = 8, REQ_DELETE_MULTICAST_ADDRESS = 9, REQ_UPDATE_STATISTICS = 10, REQ_CLEAR_STATISTICS = 11, REQ_INTERRUPT_REQUEST = 12, REQ_SET_FUNCTIONAL_ADDRESS = 13, REQ_SET_LOOKAHEAD = 14 } NdisGeneralRequest; typedef enum { SF_BROADCAST = 0x00000001L, SF_MULTICAST = 0x00000002L, SF_FUNCTIONAL = 0x00000004L, SF_PROMISCUOUS = 0x00000008L, SF_SOFT_ADDRESS = 0x00000010L, SF_STATS_CURRENT = 0x00000020L, SF_INITIATE_DIAGS = 0x00000040L, SF_LOOPBACK = 0x00000080L, SF_RECEIVE_CHAIN = 0x00000100L, SF_SOURCE_ROUTING = 0x00000200L, SF_RESET_MAC = 0x00000400L, SF_OPEN_CLOSE = 0x00000800L, SF_INTERRUPT_REQUEST = 0x00001000L, SF_SOURCE_ROUTING_BRIDGE = 0x00002000L, SF_VIRTUAL_ADDRESSES = 0x00004000L } NdisMacServiceFlags; typedef enum { REQ_INITIATE_BIND = 1, REQ_BIND = 2, REQ_INITIATE_PREBIND = 3, REQ_INITIATE_UNBIND = 4, REQ_UNBIND = 5 } NdisSysRequest; typedef enum { PM_GET_PROTOCOL_MANAGER_INFO = 1, PM_REGISTER_MODULE = 2, PM_BIND_AND_START = 3, PM_GET_PROTOCOL_MANAGER_LINKAGE = 4, PM_GET_PROTOCOL_INI_PATH = 5, PM_REGISTER_PROTOCOL_MANAGER_INFO = 6, PM_INIT_AND_REGISTER = 7, PM_UNBIND_AND_STOP = 8, PM_BIND_STATUS = 9, PM_REGISTER_STATUS = 10 } NdisProtManager; typedef enum { ERR_SUCCESS = 0x00, ERR_WAIT_FOR_RELEASE = 0x01, ERR_REQUEST_QUEUED = 0x02, ERR_FRAME_NOT_RECOGNIZED = 0x03, ERR_FRAME_REJECTED = 0x04, ERR_FORWARD_FRAME = 0x05, ERR_OUT_OF_RESOURCE = 0x06, ERR_INVALID_PARAMETER = 0x07, ERR_INVALID_FUNCTION = 0x08, ERR_NOT_SUPPORTED = 0x09, ERR_HARDWARE_ERROR = 0x0A, ERR_TRANSMIT_ERROR = 0x0B, ERR_NO_SUCH_DESTINATION = 0x0C, ERR_BUFFER_TOO_SMALL = 0x0D, ERR_ALREADY_STARTED = 0x20, ERR_INCOMPLETE_BINDING = 0x21, ERR_DRIVER_NOT_INITIALIZED = 0x22, ERR_HARDWARE_NOT_FOUND = 0x23, ERR_HARDWARE_FAILURE = 0x24, ERR_CONFIGURATION_FAILURE = 0x25, ERR_INTERRUPT_CONFLICT = 0x26, ERR_INCOMPATIBLE_MAC = 0x27, ERR_INITIALIZATION_FAILED = 0x28, ERR_NO_BINDING = 0x29, ERR_NETWORK_MAY_NOT_BE_CONNECTED = 0x2A, ERR_INCOMPATIBLE_OS_VERSION = 0x2B, ERR_ALREADY_REGISTERED = 0x2C, ERR_PATH_NOT_FOUND = 0x2D, ERR_INSUFFICIENT_MEMORY = 0x2E, ERR_INFO_NOT_FOUND = 0x2F, ERR_GENERAL_FAILURE = 0xFF } NdisError; #define NDIS_PARAM_INTEGER 0 #define NDIS_PARAM_STRING 1 #define NDIS_TX_BUF_LENGTH 8 #define NDIS_TD_BUF_LENGTH 1 #define NDIS_RX_BUF_LENGTH 8 #define NDIS_PTR_PHYSICAL 0 #define NDIS_PTR_VIRTUAL 2 #define NDIS_PATH "PROTMAN$" typedef struct _CommonChars { WORD tableSize; BYTE majorNdisVersion; /* 2 - Latest version */ BYTE minorNdisVersion; /* 0 */ WORD reserved1; BYTE majorModuleVersion; BYTE minorModuleVersion; DWORD moduleFlags; /* 0 - Binding at upper boundary supported * 1 - Binding at lower boundary supported * 2 - Dynamically bound. * 3-31 - Reserved, must be zero. */ BYTE moduleName[16]; BYTE protocolLevelUpper; /* 1 - MAC * 2 - Data Link * 3 - Network * 4 - Transport * 5 - Session * -1 - Not specified */ BYTE interfaceUpper; BYTE protocolLevelLower; /* 0 - Physical * 1 - MAC * 2 - Data Link * 3 - Network * 4 - Transport * 5 - Session * -1 - Not specified */ BYTE interfaceLower; WORD moduleId; WORD moduleDS; SystemRequest systemRequest; BYTE *serviceChars; BYTE *serviceStatus; BYTE *upperDispatchTable; BYTE *lowerDispatchTable; BYTE *reserved2; /* Must be NULL */ BYTE *reserved3; /* Must be NULL */ } CommonChars; typedef struct _MulticastList { WORD maxMulticastAddresses; WORD numberMulticastAddresses; BYTE multicastAddress[16][16]; } MulticastList; typedef struct _MacChars { WORD tableSize; BYTE macName[16]; WORD addressLength; BYTE permanentAddress[16]; BYTE currentAddress[16]; DWORD currentFunctionalAddress; MulticastList *multicastList; DWORD linkSpeed; DWORD serviceFlags; WORD maxFrameSize; DWORD txBufferSize; WORD txBufferAllocSize; DWORD rxBufferSize; WORD rxBufferAllocSize; BYTE ieeeVendor[3]; BYTE vendorAdapter; BYTE *vendorAdapterDescription; WORD interruptLevel; WORD txQueueDepth; WORD maxDataBlocks; } MacChars; typedef struct _ProtocolChars { WORD length; BYTE name[16]; WORD type; } ProtocolChars; typedef struct _MacUpperDispatch { CommonChars *backPointer; Request request; TransmitChain transmitChain; TransferData transferData; ReceiveRelease receiveRelease; IndicationOn indicationOn; IndicationOff indicationOff; } MacUpperDispatch; typedef struct _MacStatusTable { WORD tableSize; DWORD lastDiag; DWORD macStatus; WORD packetFilter; BYTE *mediaSpecificStats; DWORD lastClear; DWORD totalFramesRx; DWORD totalFramesCrc; DWORD totalBytesRx; DWORD totalDiscardBufSpaceRx; DWORD totalMulticastRx; DWORD totalBroadcastRx; DWORD obsolete1[5]; DWORD totalDiscardHwErrorRx; DWORD totalFramesTx; DWORD totalBytesTx; DWORD totalMulticastTx; DWORD totalBroadcastTx; DWORD obsolete2[2]; DWORD totalDiscardTimeoutTx; DWORD totalDiscardHwErrorTx; } MacStatusTable; typedef struct _ProtDispatch { CommonChars *backPointer; DWORD flags; /* 0 - handles non-LLC frames * 1 - handles specific-LSAP LLC frames * 2 - handles specific-LSAP LLC frames * 3-31 - reserved must be 0 */ void (*requestConfirm) (void); void (*transmitConfirm) (void); void (*receiveLookahead) (void); void (*indicationComplete) (void); void (*receiveChain) (void); void (*status) (void); } ProtDispatch; typedef struct _ReqBlock { WORD opcode; WORD status; BYTE FAR *pointer1; BYTE FAR *pointer2; WORD word1; } ReqBlock; typedef struct _TxBufDescrRec { BYTE txPtrType; BYTE dummy; WORD txDataLen; BYTE *txDataPtr; } TxBufDescrRec; typedef struct _TxBufDescr { WORD txImmedLen; BYTE *txImmedPtr; WORD txDataCount; TxBufDescrRec txBufDescrRec[NDIS_TX_BUF_LENGTH]; } TxBufDescr; typedef struct _TDBufDescrRec { BYTE tDPtrType; BYTE dummy; WORD tDDataLen; BYTE *tDDataPtr; } TDBufDescrRec; typedef struct _TDBufDescr { WORD tDDataCount; TDBufDescrRec tDBufDescrRec[NDIS_TD_BUF_LENGTH]; } TDBufDescr; typedef struct _RxBufDescrRec { WORD rxDataLen; BYTE *rxDataPtr; } RxBufDescrRec; typedef struct _RxBufDescr { WORD rxDataCount; RxBufDescrRec rxBufDescrRec[NDIS_RX_BUF_LENGTH]; } RxBufDescr; typedef struct _PktBuf { struct _PktBuf *nextLink; struct _PktBuf *prevLink; int handle; int length; int packetLength; DWORD sequence; BYTE *buffer; } PktBuf; typedef struct _CardHandle { BYTE moduleName[16]; CommonChars *common; } CardHandle; typedef struct _BindingsList { WORD numBindings; BYTE moduleName[2][16]; } BindingsList; typedef struct _FailingModules { BYTE upperModuleName[16]; BYTE lowerModuleName[16]; } FailingModules; typedef union _HardwareAddress { BYTE bytes[6]; WORD words[3]; struct { BYTE bytes[6]; } addr; } HardwareAddress; typedef struct _FddiHeader { BYTE frameControl; HardwareAddress etherDestHost; HardwareAddress etherSrcHost; } FddiHeader; typedef struct _EthernetIIHeader { HardwareAddress etherDestHost; HardwareAddress etherSrcHost; WORD etherType; } EthernetIIHeader; typedef struct _Ieee802Dot5Header { HardwareAddress etherDestHost; HardwareAddress etherSrcHost; BYTE routeInfo[30]; } Ieee802Dot5Header; typedef struct _Ieee802Dot2SnapHeader { BYTE dsap; /* 0xAA */ BYTE ssap; /* 0xAA */ BYTE control; /* 3 */ BYTE protocolId[5]; } Ieee802Dot2SnapHeader; /* * Prototypes */ extern char *NdisLastError (void); extern int NdisOpen (void); extern int NdisInit (int promis); extern int NdisRegisterAndBind (int promis); extern void NdisShutdown (void); extern void NdisCheckMacFeatures (struct _CardHandle *card); extern int NdisSendPacket (struct _PktBuf *pktBuf, int macId); /* * Assembly "glue" functions */ extern int systemRequestGlue(); extern int requestConfirmGlue(); extern int transmitConfirmGlue(); extern int receiveLookaheadGlue(); extern int indicationCompleteGlue(); extern int receiveChainGlue(); extern int statusGlue(); /* * IOCTL function */ #ifdef __SMALL__ extern int _far NdisGetLinkage (int handle, char *data, int size); #else extern int NdisGetLinkage (int handle, char *data, int size); #endif /* * NDIS callback handlers */ CALLBACK (NdisSystemRequest (DWORD,DWORD, WORD, WORD, WORD)); CALLBACK (NdisRequestConfirm ( WORD, WORD, WORD, WORD, WORD,WORD)); CALLBACK (NdisTransmitConfirm ( WORD, WORD, WORD, WORD, WORD)); CALLBACK (NdisReceiveLookahead ( WORD, WORD, WORD, BYTE*, BYTE*, WORD)); CALLBACK (NdisReceiveChain ( WORD, WORD, WORD, struct _RxBufDescr*, BYTE*, WORD)); CALLBACK (NdisStatusProc ( WORD, WORD, BYTE*, WORD,WORD)); CALLBACK (NdisIndicationComplete( WORD, WORD)); BYTE *NdisAllocStack (void); void NdisFreeStack (BYTE*); #ifdef __HIGHC__ #define RENAME_ASM_SYM(x) pragma Alias(x,"@" #x "") /* prepend `@' */ #define RENAME_C_SYM(x) pragma Alias(x,"_" #x "") /* prepend `_' */ RENAME_ASM_SYM (systemRequestGlue); RENAME_ASM_SYM (requestConfirmGlue); RENAME_ASM_SYM (transmitConfirmGlue); RENAME_ASM_SYM (receiveLookaheadGlue); RENAME_ASM_SYM (indicationCompleteGlue); RENAME_ASM_SYM (receiveChainGlue); RENAME_ASM_SYM (statusGlue); RENAME_ASM_SYM (NdisGetLinkage); RENAME_C_SYM (NdisSystemRequest); RENAME_C_SYM (NdisRequestConfirm); RENAME_C_SYM (NdisTransmitConfirm); RENAME_C_SYM (NdisReceiveLookahead); RENAME_C_SYM (NdisIndicationComplete); RENAME_C_SYM (NdisReceiveChain); RENAME_C_SYM (NdisStatusProc); RENAME_C_SYM (NdisAllocStack); RENAME_C_SYM (NdisFreeStack); #endif #endif libpcap-1.8.1/msdos/makefile.wc0000644000026300017510000000756313003771737014536 0ustar mcrmcr# # Watcom Makefile for dos-libpcap. # # Specify MODEL = `3r' or `3s' # Specify TARGET = `pharlap' or `dos4g' # # Use this makefile from the libpcap root directory. # E.g. like this: # # c:\net\pcap> wmake -f msdos\makefile.wc # MODEL = 3s TARGET = dos4g OBJDIR = msdos\$(TARGET).w$(MODEL) LIB = $(OBJDIR)\pcap.lib .EXTENSIONS: .l .y DEFS = -dDEBUG -dNDIS_DEBUG -d_U_= -dHAVE_LIMITS_H -dHAVE_STRERROR & -dHAVE_SNPRINTF -dHAVE_VSNPRINTF CC = wcc386.exe ASM = wasm.exe -$(MODEL) $(DEFS) -dDOSX -dDOS4GW -zq -bt=dos -fr=nul -d3 -s OBJS = $(OBJDIR)\grammar.obj $(OBJDIR)\scanner.obj $(OBJDIR)\pcap.obj & $(OBJDIR)\bpf_filter.obj $(OBJDIR)\bpf_imag.obj $(OBJDIR)\bpf_dump.obj & $(OBJDIR)\etherent.obj $(OBJDIR)\gencode.obj $(OBJDIR)\nametoad.obj & $(OBJDIR)\pcap-dos.obj $(OBJDIR)\pktdrvr.obj $(OBJDIR)\optimize.obj & $(OBJDIR)\savefile.obj $(OBJDIR)\inet.obj $(OBJDIR)\ndis2.obj CFLAGS = $(DEFS) $(YYDEFS) -I. -I$(%watt_root)\inc -I.\msdos\pm_drvr & -$(MODEL) -mf -zff -zgf -zq -bt=dos -fr=nul -w6 -fpi & -oilrtf -zm TEMPBIN = tmp.bin all: $(OBJDIR) $(OBJDIR)\pcap.lib $(OBJDIR): - mkdir $(OBJDIR) $(OBJDIR)\pcap.lib: $(OBJS) wlib.arg wlib -q -b -c $(OBJDIR)\pcap.lib @wlib.arg wlib.arg: msdos\makefile.wc %create $^@ for %f in ($(OBJS)) do %append $^@ +- %f $(OBJDIR)\pktdrvr.obj: msdos\pkt_stub.inc msdos\pktdrvr.c & pcap-dos.h pcap-int.h pcap.h msdos\pktdrvr.h *$(CC) $(CFLAGS) msdos\pktdrvr.c -fo=$@ $(OBJDIR)\bpf_filter.obj: bpf\net\bpf_filter.c *$(CC) $(CFLAGS) bpf\net\bpf_filter.c -fo=$@ $(OBJDIR)\ndis2.obj: msdos\ndis2.c *$(CC) $(CFLAGS) msdos\ndis2.c -fo=$@ .ERASE .c{$(OBJDIR)}.obj: *$(CC) $(CFLAGS) $[@ -fo=$@ grammar.c tokdefs.h: grammar.y bison --name-prefix=pcap_ --yacc --defines $[@ - @del grammar.c - @del tokdefs.h ren y_tab.c grammar.c ren y_tab.h tokdefs.h scanner.c: scanner.l flex -Ppcap_ -7 -o$@ $[@ msdos\pkt_stub.inc: bin2c.exe msdos\pkt_rx1.S nasm -fbin -dDEBUG -o $(TEMPBIN) -lmsdos\pkt_rx1.lst msdos\pkt_rx1.S bin2c.exe $(TEMPBIN) > $@ @del $(TEMPBIN) bin2c.exe: msdos\bin2c.c wcl $[@ clean realclean vclean: .SYMBOLIC for %f in (dos4g.w3r dos4g.w3s pharlap.w3r pharlap.w3s) do & @del %f\*.obj @del grammar.c @del tokdefs.h @del scanner.c @del bin2c.exe @del bin2c.obj @del msdos\pkt_stub.inc @echo Cleaned # # dependencies # $(OBJDIR)\bpf_filter.obj: bpf\net\bpf_filter.c pcap-int.h pcap.h pcap-bpf.h $(OBJDIR)\bpf_imag.obj: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h $(OBJDIR)\bpf_dump.obj: bpf_dump.c pcap.h pcap-bpf.h $(OBJDIR)\etherent.obj: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h $(OBJDIR)\optimize.obj: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h $(OBJDIR)\savefile.obj: savefile.c pcap-int.h pcap.h pcap-bpf.h $(OBJDIR)\pcap.obj: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h $(OBJDIR)\inet.obj: inet.c pcap-int.h pcap.h pcap-bpf.h $(OBJDIR)\grammar.obj: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h & pcap-namedb.h $(OBJDIR)\scanner.obj: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h & pcap-namedb.h tokdefs.h $(OBJDIR)\gencode.obj: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h & ethertyp.h nlpid.h llc.h gencode.h atmuni31.h sunatmpo.h ppp.h sll.h & arcnet.h pcap-namedb.h $(OBJDIR)\nametoad.obj: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h & pcap-namedb.h ethertyp.h $(OBJDIR)\pcap-dos.obj: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h & msdos\pktdrvr.h $(OBJDIR)\pktdrvr.obj: msdos\pktdrvr.c pcap-dos.h pcap-int.h & pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc $(OBJDIR)\ndis2.obj: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h & msdos\ndis2.h libpcap-1.8.1/msdos/makefile0000644000026300017510000001154513003771737014121 0ustar mcrmcr# # Makefile for dos-libpcap. NB. This makefile requires a Borland # compatible make tool. # # Targets: # Borland C 4.0+ (DOS large model) # Metaware HighC 3.3+ (PharLap 386|DosX) # .AUTODEPEND .SWAP !if "$(WATT_ROOT)" == "" !error Environment variable "WATT_ROOT" not set. !endif WATT_INC = $(WATT_ROOT)\inc DEFS = -DMSDOS -DDEBUG -DNDIS_DEBUG -D_U_= -Dinline= \ -DHAVE_STRERROR -DHAVE_LIMITS_H ASM = tasm.exe -t -l -mx -m2 -DDEBUG SOURCE = grammar.c scanner.c bpf_filt.c bpf_imag.c bpf_dump.c \ etherent.c gencode.c nametoad.c pcap-dos.c optimize.c \ savefile.c pcap.c inet.c msdos\ndis2.c msdos\pktdrvr.c \ missing\snprintf.c BORLAND_OBJ = $(SOURCE:.c=.obj) msdos\pkt_rx0.obj msdos\ndis_0.obj HIGHC_OBJ = $(SOURCE:.c=.o32) msdos\pkt_rx0.o32 all: @echo Usage: make pcap_bc.lib or pcap_hc.lib pcap_bc.lib: bcc.arg $(BORLAND_OBJ) pcap_bc pcap_hc.lib: hc386.arg $(HIGHC_OBJ) 386lib $< @&&| -nowarn -nobackup -twocase -replace $(HIGHC_OBJ) | pcap_bc: $(BORLAND_OBJ) @tlib pcap_bc.lib /C @&&| -+$(**:.obj=-+) | .c.obj: bcc.exe @bcc.arg -o$*.obj $*.c .c.o32: hc386.exe @hc386.arg -o $*.o32 $*.c .asm.obj: $(ASM) $*.asm, $*.obj .asm.o32: $(ASM) -DDOSX=1 $*.asm, $*.o32 scanner.c: scanner.l flex -Ppcap_ -7 -oscanner.c scanner.l grammar.c tokdefs.h: grammar.y bison --name-prefix=pcap_ --yacc --defines grammar.y - @del grammar.c - @del tokdefs.h ren y_tab.c grammar.c ren y_tab.h tokdefs.h bcc.arg: msdos\Makefile @copy &&| $(DEFS) -ml -c -v -3 -O2 -po -RT- -w- -I$(WATT_INC) -I. -I.\msdos\pm_drvr -H=$(TEMP)\bcc.sym | $< hc386.arg: msdos\Makefile @copy &&| # -DUSE_32BIT_DRIVERS $(DEFS) -DDOSX=1 -w3 -c -g -O5 -I$(WATT_INC) -I. -I.\msdos\pm_drvr -Hsuffix=.o32 -Hnocopyr -Hpragma=Offwarn(491,553,572) -Hon=Recognize_library # make memcpy/strlen etc. inline -Hoff=Behaved # turn off some optimiser warnings | $< clean: @del *.obj @del *.o32 @del *.lst @del *.map @del bcc.arg @del hc386.arg @del grammar.c @del tokdefs.h @del scanner.c @echo Cleaned # # dependencies # pkt_rx0.obj: msdos\pkt_rx0.asm bpf_filt.obj: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h gnuc.h bpf_imag.obj: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h bpf_dump.obj: bpf_dump.c pcap.h pcap-bpf.h etherent.obj: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h optimize.obj: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h savefile.obj: savefile.c pcap-int.h pcap.h pcap-bpf.h pcap.obj: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h inet.obj: inet.c pcap-int.h pcap.h pcap-bpf.h grammar.obj: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ pf.h pcap-namedb.h scanner.obj: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ pcap-namedb.h tokdefs.h gencode.obj: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ ethertype.h nlpid.h llc.h gencode.h atmuni31.h sunatmpos.h ppp.h sll.h \ arcnet.h pf.h pcap-namedb.h nametoad.obj: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ pcap-namedb.h ethertype.h pcap-dos.obj: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h \ msdos\pktdrvr.h pktdrvr.obj: msdos\pktdrvr.c gnuc.h pcap-dos.h pcap-int.h \ pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc ndis2.obj: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ msdos\ndis2.h pkt_rx0.o32: msdos\pkt_rx0.asm bpf_filt.o32: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h gnuc.h bpf_imag.o32: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h bpf_dump.o32: bpf_dump.c pcap.h pcap-bpf.h etherent.o32: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h optimize.o32: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h savefile.o32: savefile.c pcap-int.h pcap.h pcap-bpf.h pcap.o32: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h inet.o32: inet.c pcap-int.h pcap.h pcap-bpf.h grammar.o32: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ pf.h pcap-namedb.h scanner.o32: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ pcap-namedb.h tokdefs.h gencode.o32: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ ethertype.h nlpid.h llc.h gencode.h atmuni31.h sunatmpos.h ppp.h sll.h \ arcnet.h pf.h pcap-namedb.h nametoad.o32: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ pcap-namedb.h ethertype.h pcap-dos.o32: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h \ msdos\pktdrvr.h pktdrvr.o32: msdos\pktdrvr.c gnuc.h pcap-dos.h pcap-int.h \ pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc ndis2.o32: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ msdos\ndis2.h libpcap-1.8.1/msdos/makefile.dj0000644000026300017510000000661713003771737014521 0ustar mcrmcr# # GNU Makefile for DOS-libpcap. djgpp version. # # Use this makefile from the libpcap root directory. # E.g. like this: # # c:\net\pcap> make -f msdos/makefile.dj # # Note: you should do a "set LFN=y" before running this makefile. # VPATH = missing msdos bpf/net PREREQUISITES = scanner.c grammar.c tokdefs.h version.h msdos/pkt_stub.inc include ./msdos/common.dj DRIVER_DIR = ./msdos/pm_drvr CFLAGS += -DDEBUG -DNDIS_DEBUG -DHAVE_LIMITS_H -DHAVE_STRERROR -DHAVE_SNPRINTF -DHAVE_VSNPRINTF\ -D_U_='__attribute__((unused))' CFLAGS += -Dyylval=pcap_lval # -DBDEBUG -DNDEBUG SOURCES = grammar.c scanner.c bpf/net/bpf_filter.c bpf_image.c bpf_dump.c \ etherent.c gencode.c nametoaddr.c pcap-common.c pcap-dos.c optimize.c \ savefile.c pcap.c sf-pcap.c sf-pcap-ng.c inet.c \ msdos/pktdrvr.c msdos/ndis2.c # missing/snprintf.c OBJECTS = $(addprefix $(OBJ_DIR)/, $(notdir $(SOURCES:.c=.o))) TEMPBIN = tmp.bin ifeq ($(USE_32BIT_DRIVERS),1) PM_OBJECTS = $(addprefix $(OBJ_DIR)/, \ printk.o pci.o pci-scan.o bios32.o dma.o irq.o intwrap.o \ lock.o kmalloc.o quirks.o timer.o net_init.o) # # Static link of drivers # ifeq ($(USE_32BIT_MODULES),0) PM_OBJECTS += $(addprefix $(OBJ_DIR)/, \ accton.o 8390.o 3c503.o 3c509.o 3c59x.o 3c515.o \ 3c575_cb.o 3c90x.o ne.o wd.o cs89x0.o rtl8139.o) endif endif TARGETS = msdos/bin2c.exe libpcap.a filtertest.exe findalldevstest.exe \ nonblocktest.exe opentest.exe all: $(TARGETS) @echo 'Welcome to libpcap/djgpp with samples.' ifeq ($(USE_32BIT_DRIVERS),1) $(PM_OBJECTS): $(MAKE) -f Makefile.dj -C $(DRIVER_DIR) $(notdir $@) endif libpcap.a: version.h $(OBJECTS) $(PM_OBJECTS) rm -f $@ ar rs $@ $^ filtertest.exe: tests/filtertest.c libpcap.a $(CC) $(CFLAGS) -Din_addr_t=u_long -o $@ $^ $(WATT32_ROOT)/lib/libwatt.a @echo findalldevstest.exe: tests/findalldevstest.c libpcap.a $(CC) $(CFLAGS) -o $@ $^ $(WATT32_ROOT)/lib/libwatt.a @echo nonblocktest.exe: tests/nonblocktest.c libpcap.a $(CC) $(CFLAGS) -o $@ $^ $(WATT32_ROOT)/lib/libwatt.a @echo opentest.exe: tests/opentest.c libpcap.a $(CC) $(CFLAGS) -o $@ $^ $(WATT32_ROOT)/lib/libwatt.a @echo msdos/pkt_stub.inc: msdos/bin2c.exe msdos/pkt_rx1.S $(ASM) -o $(TEMPBIN) -lmsdos/pkt_rx1.lst msdos/pkt_rx1.S ./msdos/bin2c $(TEMPBIN) > $@ rm -f $(TEMPBIN) grammar.c tokdefs.h: grammar.y rm -f grammar.c tokdefs.h $(YACC) --name-prefix=pcap_ --yacc --defines grammar.y mv -f y.tab.c grammar.c mv -f y.tab.h tokdefs.h version.h: ./VERSION @echo '/* Generated from VERSION. Do not edit */' > $@ sed -e 's/.*/static char pcap_version_string[] = "libpcap (&)";/' ./VERSION >> $@ scanner.c: scanner.l $(LEX) -Ppcap_ -7 -t $^ > $@ @echo msdos/bin2c.exe: msdos/bin2c.c $(CC) $*.c -o $*.exe clean: rm -f $(OBJECTS) msdos/pkt_rx1.lst Makefile.bak .depend.dj $(PREREQUISITES) # $(MAKE) -f Makefile.dj -C $(DRIVER_DIR) clean vclean: clean rm -f $(TARGETS) -rmdir $(OBJ_DIR) # # Manually generated dependencies # msdos/pktdrvr.c: msdos/pkt_stub.inc scanner.c: scanner.l grammar.c tokdefs.h: grammar.y grammar.h: grammar.y scanner.l: pcap-int.h pcap-namedb.h gencode.h grammar.h grammar.y: pcap-int.h gencode.h pcap-namedb.h # # Generate dependencies. # REPLACE = sed -e 's/\(.*\)\.o: /\n$$(OBJ_DIR)\/\1.o: /' depend: $(PREREQUISITES) $(CC) -MM $(CFLAGS) $(SOURCES) | $(REPLACE) > .depend.dj -include .depend.dj libpcap-1.8.1/msdos/readme.dos0000644000026300017510000001374613003771737014372 0ustar mcrmcrlibpcap for DOS --------------- This file contains some notes on building and using libpcap for MS-DOS. Look in `README' and `pcap.man' for usage and details. These targets are supported: - Borland C 4.0+ small or large model. - Metaware HighC 3.1+ with PharLap DOS-extender - GNU C 2.7+ with djgpp 2.01+ DOS extender - Watcom C 11.x with DOS4GW extender Note: the files in the libpcap.zip contains short truncated filenames. So for djgpp to work with these, disable the use of long file names by setting "LFN=n" in the environment. On the other hand, if you get libpcap from Github or the official libpcap.tar.gz, some filenames are beyond 8+3. In this case set "LFN=y". Files specific to DOS are pcap-dos.[ch] and the assembly and C files in the MSDOS sub-directory. Remember to built the libpcap library from the top install directory. And not from the MSDOS sub-directory. Note for djgpp users: If you got the libpcap from the official site www.tcpdump, then that distribution does NOT contain any sources for building 32-bit drivers. Instead get the full version at http://www.watt-32.net/pcap/libpcap.zip and set "USE_32BIT_DRIVERS = 1" in msdos\common.dj. Requirements ------------ DOS-libpcap currently only works reliably with a real-mode Ethernet packet- driver. This driver must be installed prior to using any program (e.g. tcpdump) compiled with libpcap. Work is underway to implement protected- mode drivers for 32-bit targets (djgpp only). The 3Com 3c509 driver is working almost perfectly. Due to lack of LAN-cards, I've not had the opportunity to test other drivers. These 32-bit drivers are modified Linux drivers. Required packages ----------------- The following packages and tools must be present for all targets. 1. Watt-32 tcp/ip library. This library is *not* used to send or receive network data. It's mostly used to access the 'hosts' file and other features. Get 'watt32s*.zip' at: http://www.watt-32.net 2. Exception handler and disassember library (libexc.a) is needed if "USE_EXCEPT = 1" in common.dj. Available at: http://www.watt-32.net/misc/exc_dx07.zip 3. Flex & Bison is used to generate parser for the filter handler pcap_compile: ftp://ftp.delorie.com/pub/djgpp/current/v2gnu/flx254b.zip ftp://ftp.delorie.com/pub/djgpp/current/v2gnu/bsn241b.zip 4. NASM assembler v 0.98 or later is required when building djgpp and Watcom targets: http://www.nasm.us/ 5. sed (Stream Editor) is required for doing `make depend'. It's available at: ftp://ftp.delorie.com/pub/djgpp/current/v2gnu/sed422b.zip A touch tool to update the time-stamp of a file. E.g.: ftp://ftp.delorie.com/pub/djgpp/current/v2gnu/grep29b.zip 6. For djgpp rm.exe and cp.exe are required. These should already be part of your djgpp installation. Also required (experimental at the time) for djgpp is DLX 2.91 or later. This tool is for the generation of dynamically loadable modules. Compiling libpcap ----------------- Follow these steps in building libpcap: 1. Make sure you've installed Watt-32 properly (see it's `INSTALL' file). During that installation a environment variable `WATT_ROOT' is set. This variable is used for building libpcap also (`WATT_INC' is deducted from `WATT_ROOT'). djgpp users should also define environment variables `C_INCLUDE_PATH' and `LIBRARY_PATH' to point to the include directory and library directory respectively. E.g. put this in your AUTOEXEC.BAT: set C_INCLUDE_PATH=c:/net/watt/inc set LIBRARY_PATH=c:/net/watt/lib 2. Revise the msdos/common.dj file for your djgpp/gcc installation; - change the value of `GCCLIB' to match location of libgcc.a. - set `USE_32BIT_DRIVERS = 1' to build 32-bit driver objects. 3. Build pcap by using appropriate makefile. For djgpp, use: `make -f msdos/makefile.dj' (i.e. GNU `make') For a Watcom target say: `wmake -f msdos\makefile.wc' For a Borland target say: `maker -f msdos\Makefile pcap_bc.lib' (Borland's `maker.exe') And for a HighC/Pharlap target say: `maker -f msdos\Makefile pcap_hc.lib' (Borland's `maker.exe') You might like to change some `CFLAGS' -- only `DEBUG' define currently have any effect. It shows a rotating "fan" in upper right corner of screen. Remove `DEBUG' if you don't like it. You could add `-fomit-frame-pointer' to `CFLAGS' to speed up the generated code. But note, this makes debugging and crash-traceback difficult. Only add it if you're fully confident your application is 100% stable. Note: Code in `USE_NDIS2' does not work at the moment. 4. The resulting library is put in current directory. There's some test-program for `libpcap': `filtertest.exe', `findalldevstest.exe', `nonblocktest.exe' and `opentest.exe'. But linking the library with `tcpdump' is the ultimate test. DOS/djgpp should now hopefully be a supported target. Get the sources at: http://www.tcpdump.org/ or https://github.com/the-tcpdump-group/tcpdump/ (click on the 'Download ZIP' on the right side of that page.) Extensions to libpcap --------------------- I've included some extra functions to DOS-libpcap: `pcap_config_hook (const char *keyword, const char *value)' : Allows an application to set values of internal libpcap variables. `keyword' and an associated `value' should be present in the `debug_tab[]' array in pcap-dos.c (currently only used to set debug-levels and parameters for the 32-bit network drivers.) Thus an application using DOS-libpcap can override the default value during it's configure process (see tcpdump's msdos/config.c file for an extended example). `pcap_set_wait (pcap_t *, void (*)(void), int)' : Only effective when reading offline traffic from dump-files. Function `pcap_offline_read()' will wait (and optionally yield) before printing next packet. This will simulate the pace the packets where actually recorded. Happy sniffing ! Gisle Vanem October 1999, 2004, 2006, 2013 libpcap-1.8.1/msdos/ndis_0.asm0000644000026300017510000001020213003771737014264 0ustar mcrmcrPAGE 60,132 NAME NDIS_0 ifdef DOSX .386 _TEXT SEGMENT PUBLIC DWORD USE16 'CODE' _TEXT ENDS _DATA SEGMENT PUBLIC DWORD USE16 'CODE' _DATA ENDS _TEXT32 SEGMENT PUBLIC BYTE USE32 'CODE' _TEXT32 ENDS CB_DSEG EQU ; DOSX is tiny-model D_SEG EQU <_TEXT SEGMENT> D_END EQU <_TEXT ENDS> ASSUME CS:_TEXT,DS:_TEXT PUSHREGS equ POPREGS equ PUBPROC macro name align 4 public @&name @&name label near endm else .286 _TEXT SEGMENT PUBLIC DWORD 'CODE' _TEXT ENDS _DATA SEGMENT PUBLIC DWORD 'DATA' _DATA ENDS CB_DSEG EQU ; 16bit is small/large model D_SEG EQU <_DATA SEGMENT> D_END EQU <_DATA ENDS> ASSUME CS:_TEXT,DS:_DATA PUSHREGS equ POPREGS equ PUBPROC macro name public _&name _&name label far endm endif ;------------------------------------------- D_SEG D_END _TEXT SEGMENT EXTRN _NdisSystemRequest : near EXTRN _NdisRequestConfirm : near EXTRN _NdisTransmitConfirm : near EXTRN _NdisReceiveLookahead : near EXTRN _NdisIndicationComplete : near EXTRN _NdisReceiveChain : near EXTRN _NdisStatusProc : near EXTRN _NdisAllocStack : near EXTRN _NdisFreeStack : near ; ; *ALL* interrupt threads come through this macro. ; CALLBACK macro callbackProc, argsSize pushf PUSHREGS ;; Save the registers push es push ds mov ax,CB_DSEG ;; Load DS mov ds,ax call _NdisAllocStack ;; Get and install a stack. mov bx,ss ;; Save off the old stack in other regs mov cx,sp mov ss,dx ;; Install the new one mov sp,ax push bx ;; Save the old one on to the new stack push cx sub sp,&argsSize ;; Allocate space for arguments on the stack mov ax,ss ;; Set up the destination for the move mov es,ax mov di,sp mov ds,bx ;; Set up the source for the move. mov si,cx add si,4+6+32 mov cx,&argsSize ;; Move the arguments to the stack. shr cx,1 cld rep movsw mov ax,CB_DSEG ;; Set my data segment again. mov ds,ax call &callbackProc ;; Call the real callback. pop di ;; Pop off the old stack pop si mov bx,ss ;; Save off the current allocated stack. mov cx,sp mov ss,si ;; Restore the old stack mov sp,di push ax ;; Save the return code push bx ;; Free the stack. Push the pointer to it push cx call _NdisFreeStack add sp,4 pop ax ;; Get the return code back add di,32 ;; Get a pointer to ax on the stack mov word ptr ss:[di],ax pop ds pop es POPREGS popf endm ; ; Define all of the callbacks for the NDIS procs. ; PUBPROC systemRequestGlue CALLBACK _NdisSystemRequest,14 RETF PUBPROC requestConfirmGlue CALLBACK _NdisRequestConfirm,12 RETF PUBPROC transmitConfirmGlue CALLBACK _NdisTransmitConfirm,10 RETF PUBPROC receiveLookaheadGlue CALLBACK _NdisReceiveLookahead,16 RETF PUBPROC indicationCompleteGlue CALLBACK _NdisIndicationComplete,4 RETF PUBPROC receiveChainGlue CALLBACK _NdisReceiveChain,16 RETF PUBPROC statusGlue CALLBACK _NdisStatusProc,12 RETF ; ; int FAR NdisGetLinkage (int handle, char *data, int size); ; ifdef DOSX PUBPROC NdisGetLinkage push ebx mov ebx, [esp+8] ; device handle mov eax, 4402h ; IOCTRL read function mov edx, [esp+12] ; DS:EDX -> result data mov ecx, [esp+16] ; ECX = length int 21h pop ebx jc @fail xor eax, eax @fail: ret else PUBPROC NdisGetLinkage enter 0, 0 mov bx, [bp+6] mov ax, 4402h mov dx, [bp+8] mov cx, [bp+12] int 21h jc @fail xor ax, ax @fail: leave retf endif ENDS END libpcap-1.8.1/Makefile-devel-adds0000644000026300017510000000114613003771737014736 0ustar mcrmcr# # Auto-regenerate configure script or Makefile when things change. # From autoconf.info . Works best with GNU Make. # ${srcdir}/configure: configure.ac aclocal.m4 cd ${srcdir} && autoconf # autoheader might not change config.h.in, so touch a stamp file. ${srcdir}/config.h.in: ${srcdir}/stamp-h.in ${srcdir}/stamp-h.in: configure.ac aclocal.m4 cd ${srcdir} && autoheader echo timestamp > ${srcdir}/stamp-h.in config.h: stamp-h stamp-h: ${srcdir}/config.h.in config.status ./config.status Makefile: Makefile.in config.status ./config.status config.status: ${srcdir}/configure ./config.status --recheck libpcap-1.8.1/pcap_list_tstamp_types.3pcap.in0000644000026300017510000000501713003771737017420 0ustar mcrmcr.\" .\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_LIST_TSTAMP_TYPES 3PCAP "22 August 2010" .SH NAME pcap_list_tstamp_types, pcap_free_tstamp_types \- get a list of time stamp types supported by a capture device, and free that list .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp); void pcap_free_tstamp_types(int *tstamp_types); .ft .fi .SH DESCRIPTION .B pcap_list_tstamp_types() is used to get a list of the supported time stamp types of the interface associated with the pcap descriptor. .B pcap_list_tstamp_types() allocates an array to hold the list and sets .I *tstamp_typesp to point to the array. See .BR pcap-tstamp (@MAN_MISC_INFO@) for a list of all the time stamp types. .PP The caller is responsible for freeing the array with .BR pcap_free_tstamp_types() , which frees the list pointed to by .IR tstamp_types . .SH RETURN VALUE .B pcap_list_tstamp_types() returns the number of time stamp types in the array on success and .B PCAP_ERROR on failure. A return value of zero means that you cannot specify a time stamp type; you are limited to the capture device's default time stamp type. If .B PCAP_ERROR is returned, .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO pcap(3PCAP), pcap_geterr(3PCAP), pcap_tstamp_type_val_to_name(3PCAP), pcap-tstamp(@MAN_MISC_INFO@) libpcap-1.8.1/gen_version_c.sh0000755000026300017510000000036713003771737014453 0ustar mcrmcr#! /bin/sh echo '#include ' > "$2" echo 'PCAP_API_DEF' >> "$2" if grep GIT "$1" >/dev/null; then read ver <"$1" echo $ver | tr -d '\012' date +_%Y_%m_%d else cat "$1" fi | sed -e 's/.*/char pcap_version[] = "&";/' >> "$2" libpcap-1.8.1/pcap-rpcap.c0000644000026300017510000022334113003771737013465 0ustar mcrmcr/* * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino, CACE Technologies * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* for strlen(), ... */ #include /* for malloc(), free(), ... */ #include /* for functions with variable number of arguments */ #include /* for the errno variable */ #include "pcap-int.h" #include "pcap-rpcap.h" #include "sockutils.h" /* * \file pcap-rpcap.c * * This file keeps all the new funtions that are needed for the RPCAP protocol. * Almost all the pcap functions need to be modified in order to become compatible * with the RPCAP protocol. However, you can find here only the ones that are completely new. * * This file keeps also the functions that are 'private', i.e. are needed by the RPCAP * protocol but are not exported to the user. * * \warning All the RPCAP functions that are allowed to return a buffer containing * the error description can return max PCAP_ERRBUF_SIZE characters. * However there is no guarantees that the string will be zero-terminated. * Best practice is to define the errbuf variable as a char of size 'PCAP_ERRBUF_SIZE+1' * and to insert manually a NULL character at the end of the buffer. This will * guarantee that no buffer overflows occur even if we use the printf() to show * the error on the screen. */ #define PCAP_STATS_STANDARD 0 /* Used by pcap_stats_remote to see if we want standard or extended statistics */ #define PCAP_STATS_EX 1 /* Used by pcap_stats_remote to see if we want standard or extended statistics */ /* Keeps a list of all the opened connections in the active mode. */ struct activehosts *activeHosts; /* * Private data for capturing on WinPcap devices. */ struct pcap_win { int nonblock; int rfmon_selfstart; /* a flag tells whether the monitor mode is set by itself */ int filtering_in_kernel; /* using kernel filter */ #ifdef HAVE_DAG_API int dag_fcs_bits; /* Number of checksum bits from link layer */ #endif }; /**************************************************** * * * Locally defined functions * * * ****************************************************/ static int rpcap_checkver(SOCKET sock, struct rpcap_header *header, char *errbuf); static struct pcap_stat *rpcap_stats_remote(pcap_t *p, struct pcap_stat *ps, int mode); static int pcap_pack_bpffilter(pcap_t *fp, char *sendbuf, int *sendbufidx, struct bpf_program *prog); static int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog); static int pcap_updatefilter_remote(pcap_t *fp, struct bpf_program *prog); static int pcap_setfilter_remote(pcap_t *fp, struct bpf_program *prog); static int pcap_setsampling_remote(pcap_t *p); /**************************************************** * * * Function bodies * * * ****************************************************/ /* * \ingroup remote_pri_func * * \brief It traslates (i.e. de-serializes) a 'sockaddr_storage' structure from * the network byte order to the host byte order. * * It accepts a 'sockaddr_storage' structure as it is received from the network and it * converts it into the host byte order (by means of a set of ntoh() ). * The function will allocate the 'sockaddrout' variable according to the address family * in use. In case the address does not belong to the AF_INET nor AF_INET6 families, * 'sockaddrout' is not allocated and a NULL pointer is returned. * This usually happens because that address does not exist on the other host, so the * RPCAP daemon sent a 'sockaddr_storage' structure containing all 'zero' values. * * \param sockaddrin: a 'sockaddr_storage' pointer to the variable that has to be * de-serialized. * * \param sockaddrout: a 'sockaddr_storage' pointer to the variable that will contain * the de-serialized data. The structure returned can be either a 'sockaddr_in' or 'sockaddr_in6'. * This variable will be allocated automatically inside this function. * * \param errbuf: a pointer to a user-allocated buffer (of size PCAP_ERRBUF_SIZE) * that will contain the error message (in case there is one). * * \return '0' if everything is fine, '-1' if some errors occurred. Basically, the error * can be only the fact that the malloc() failed to allocate memory. * The error message is returned in the 'errbuf' variable, while the deserialized address * is returned into the 'sockaddrout' variable. * * \warning This function supports only AF_INET and AF_INET6 address families. * * \warning The sockaddrout (if not NULL) must be deallocated by the user. */ int rpcap_deseraddr(struct sockaddr_storage *sockaddrin, struct sockaddr_storage **sockaddrout, char *errbuf) { /* Warning: we support only AF_INET and AF_INET6 */ if (ntohs(sockaddrin->ss_family) == AF_INET) { struct sockaddr_in *sockaddr; sockaddr = (struct sockaddr_in *) sockaddrin; sockaddr->sin_family = ntohs(sockaddr->sin_family); sockaddr->sin_port = ntohs(sockaddr->sin_port); (*sockaddrout) = (struct sockaddr_storage *) malloc(sizeof(struct sockaddr_in)); if ((*sockaddrout) == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); return -1; } memcpy(*sockaddrout, sockaddr, sizeof(struct sockaddr_in)); return 0; } if (ntohs(sockaddrin->ss_family) == AF_INET6) { struct sockaddr_in6 *sockaddr; sockaddr = (struct sockaddr_in6 *) sockaddrin; sockaddr->sin6_family = ntohs(sockaddr->sin6_family); sockaddr->sin6_port = ntohs(sockaddr->sin6_port); sockaddr->sin6_flowinfo = ntohl(sockaddr->sin6_flowinfo); sockaddr->sin6_scope_id = ntohl(sockaddr->sin6_scope_id); (*sockaddrout) = (struct sockaddr_storage *) malloc(sizeof(struct sockaddr_in6)); if ((*sockaddrout) == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); return -1; } memcpy(*sockaddrout, sockaddr, sizeof(struct sockaddr_in6)); return 0; } /* It is neither AF_INET nor AF_INET6 */ *sockaddrout = NULL; return 0; } /* \ingroup remote_pri_func * * \brief It reads a packet from the network socket. This does not make use of * callback (hence the "nocb" string into its name). * * This function is called by the several pcap_next_ex() when they detect that * we have a remote capture and they are the client side. In that case, they need * to read packets from the socket. * * Parameters and return values are exactly the same of the pcap_next_ex(). * * \warning By choice, this function does not make use of semaphores. A smarter * implementation should put a semaphore into the data thread, and a signal will * be raised as soon as there is data into the socket buffer. * However this is complicated and it does not bring any advantages when reading * from the network, in which network delays can be much more important than * these optimizations. Therefore, we chose the following approach: * - the 'timeout' chosen by the user is split in two (half on the server side, * with the usual meaning, and half on the client side) * - this function checks for packets; if there are no packets, it waits for * timeout/2 and then it checks again. If packets are still missing, it returns, * otherwise it reads packets. */ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr **pkt_header, u_char **pkt_data) { struct rpcap_header *header; /* general header according to the RPCAP format */ struct rpcap_pkthdr *net_pkt_header; /* header of the packet */ char netbuf[RPCAP_NETBUF_SIZE]; /* size of the network buffer in which the packet is copied, just for UDP */ uint32 totread; /* number of bytes (of payload) currently read from the network (referred to the current pkt) */ int nread; int retval; /* generic return value */ /* Structures needed for the select() call */ fd_set rfds; /* set of socket descriptors we have to check */ struct timeval tv; /* maximum time the select() can block waiting for data */ struct pcap_md *md; /* structure used when doing a remote live capture */ md = (struct pcap_md *) ((u_char*)p->priv + sizeof(struct pcap_win)); /* * Define the read timeout, to be used in the select() * 'timeout', in pcap_t, is in milliseconds; we have to convert it into sec and microsec */ tv.tv_sec = p->opt.timeout / 1000; tv.tv_usec = (p->opt.timeout - tv.tv_sec * 1000) * 1000; /* Watch out sockdata to see if it has input */ FD_ZERO(&rfds); /* * 'fp->rmt_sockdata' has always to be set before calling the select(), * since it is cleared by the select() */ FD_SET(md->rmt_sockdata, &rfds); retval = select((int) md->rmt_sockdata + 1, &rfds, NULL, NULL, &tv); if (retval == -1) { sock_geterror("select(): ", p->errbuf, PCAP_ERRBUF_SIZE); return -1; } /* There is no data waiting, so return '0' */ if (retval == 0) return 0; /* * data is here; so, let's copy it into the user buffer. * I'm going to read a new packet; so I reset the number of bytes (payload only) read */ totread = 0; /* * We have to define 'header' as a pointer to a larger buffer, * because in case of UDP we have to read all the message within a single call */ header = (struct rpcap_header *) netbuf; net_pkt_header = (struct rpcap_pkthdr *) (netbuf + sizeof(struct rpcap_header)); if (md->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) { /* Read the entire message from the network */ if (sock_recv(md->rmt_sockdata, netbuf, RPCAP_NETBUF_SIZE, SOCK_RECEIVEALL_NO, p->errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; } else { if (sock_recv(md->rmt_sockdata, netbuf, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, p->errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; } /* Checks if the message is correct */ retval = rpcap_checkmsg(p->errbuf, md->rmt_sockdata, header, RPCAP_MSG_PACKET, 0); if (retval != RPCAP_MSG_PACKET) /* the message is not the one expected */ { switch (retval) { case -3: /* Unrecoverable network error */ return -1; /* Do nothing; just exit from here; the error code is already into the errbuf */ case -2: /* The other endpoint sent a message that is not allowed here */ case -1: /* The other endpoint has a version number that is not compatible with our */ return 0; /* Return 'no packets received' */ default: SOCK_ASSERT("Internal error", 1); return 0; /* Return 'no packets received' */ } } /* In case of TCP, read the remaining of the packet from the socket */ if (!(md->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)) { /* Read the RPCAP packet header from the network */ nread = sock_recv(md->rmt_sockdata, (char *)net_pkt_header, sizeof(struct rpcap_pkthdr), SOCK_RECEIVEALL_YES, p->errbuf, PCAP_ERRBUF_SIZE); if (nread == -1) return -1; totread += nread; } if ((ntohl(net_pkt_header->caplen) + sizeof(struct pcap_pkthdr)) <= p->bufsize) { /* Initialize returned structures */ *pkt_header = (struct pcap_pkthdr *) p->buffer; *pkt_data = (u_char*)p->buffer + sizeof(struct pcap_pkthdr); (*pkt_header)->caplen = ntohl(net_pkt_header->caplen); (*pkt_header)->len = ntohl(net_pkt_header->len); (*pkt_header)->ts.tv_sec = ntohl(net_pkt_header->timestamp_sec); (*pkt_header)->ts.tv_usec = ntohl(net_pkt_header->timestamp_usec); /* * I don't update the counter of the packets dropped by the network since we're using TCP, * therefore no packets are dropped. Just update the number of packets received correctly */ md->TotCapt++; /* Copies the packet into the data buffer */ if (md->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) { unsigned int npkt; /* * In case of UDP the packet has already been read, we have to copy it into 'buffer'. * Another option should be to declare 'netbuf' as 'static'. However this prevents * using several pcap instances within the same process (because the static buffer is shared among * all processes) */ memcpy(*pkt_data, netbuf + sizeof(struct rpcap_header) + sizeof(struct rpcap_pkthdr), (*pkt_header)->caplen); /* We're using UDP, so we need to update the counter of the packets dropped by the network */ npkt = ntohl(net_pkt_header->npkt); if (md->TotCapt != npkt) { md->TotNetDrops += (npkt - md->TotCapt); md->TotCapt = npkt; } } else { /* In case of TCP, read the remaining of the packet from the socket */ nread = sock_recv(md->rmt_sockdata, *pkt_data, (*pkt_header)->caplen, SOCK_RECEIVEALL_YES, p->errbuf, PCAP_ERRBUF_SIZE); if (nread == -1) return -1; totread += nread; /* Checks if all the data has been read; if not, discard the data in excess */ /* This check has to be done only on TCP connections */ if (totread != ntohl(header->plen)) sock_discard(md->rmt_sockdata, ntohl(header->plen) - totread, NULL, 0); } /* Packet read successfully */ return 1; } else { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Received a packet that is larger than the internal buffer size."); return -1; } } /* \ingroup remote_pri_func * * \brief It reads a packet from the network socket. * * This function is called by the several pcap_read() when they detect that * we have a remote capture and they are the client side. In that case, they need * to read packets from the socket. * * This function relies on the pcap_read_nocb_remote to deliver packets. The * difference, here, is that as soon as a packet is read, it is delivered * to the application by means of a callback function. * * Parameters and return values are exactly the same of the pcap_read(). */ static int pcap_read_remote(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct pcap_pkthdr *pkt_header; u_char *pkt_data; int n = 0; while ((n < cnt) || (cnt < 0)) { if (pcap_read_nocb_remote(p, &pkt_header, &pkt_data) == 1) { (*callback)(user, pkt_header, pkt_data); n++; } else return n; } return n; } /* \ingroup remote_pri_func * * \brief It sends a CLOSE command to the capture server. * * This function is called when the user wants to close a pcap_t adapter. * In case we're capturing from the network, it sends a command to the other * peer that says 'ok, let's stop capturing'. * This function is called automatically when the user calls the pcap_close(). * * Parameters and return values are exactly the same of the pcap_close(). * * \warning Since we're closing the connection, we do not check for errors. */ static void pcap_cleanup_remote(pcap_t *fp) { struct rpcap_header header; /* header of the RPCAP packet */ struct activehosts *temp; /* temp var needed to scan the host list chain, to detect if we're in active mode */ int active = 0; /* active mode or not? */ struct pcap_md *md; /* structure used when doing a remote live capture */ md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win)); /* detect if we're in active mode */ temp = activeHosts; while (temp) { if (temp->sockctrl == md->rmt_sockctrl) { active = 1; break; } temp = temp->next; } if (!active) { rpcap_createhdr(&header, RPCAP_MSG_CLOSE, 0, 0); /* I don't check for errors, since I'm going to close everything */ sock_send(md->rmt_sockctrl, (char *)&header, sizeof(struct rpcap_header), NULL, 0); } else { rpcap_createhdr(&header, RPCAP_MSG_ENDCAP_REQ, 0, 0); /* I don't check for errors, since I'm going to close everything */ sock_send(md->rmt_sockctrl, (char *)&header, sizeof(struct rpcap_header), NULL, 0); /* wait for the answer */ /* Don't check what we got, since the present libpcap does not uses this pcap_t anymore */ sock_recv(md->rmt_sockctrl, (char *)&header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, NULL, 0); if (ntohl(header.plen) != 0) sock_discard(md->rmt_sockctrl, ntohl(header.plen), NULL, 0); } if (md->rmt_sockdata) { sock_close(md->rmt_sockdata, NULL, 0); md->rmt_sockdata = 0; } if ((!active) && (md->rmt_sockctrl)) sock_close(md->rmt_sockctrl, NULL, 0); md->rmt_sockctrl = 0; if (md->currentfilter) { free(md->currentfilter); md->currentfilter = NULL; } /* To avoid inconsistencies in the number of sock_init() */ sock_cleanup(); } /* \ingroup remote_pri_func * * \brief It retrieves network statistics from the other peer. * * This function is just a void cointainer, since the work is done by the rpcap_stats_remote(). * See that funcion for more details. * * Parameters and return values are exactly the same of the pcap_stats(). */ static int pcap_stats_remote(pcap_t *p, struct pcap_stat *ps) { struct pcap_stat *retval; retval = rpcap_stats_remote(p, ps, PCAP_STATS_STANDARD); if (retval) return 0; else return -1; } #ifdef _WIN32 /* \ingroup remote_pri_func * * \brief It retrieves network statistics from the other peer. * * This function is just a void cointainer, since the work is done by the rpcap_stats_remote(). * See that funcion for more details. * * Parameters and return values are exactly the same of the pcap_stats_ex(). */ static struct pcap_stat *pcap_stats_ex_remote(pcap_t *p, int *pcap_stat_size) { *pcap_stat_size = sizeof (p->stat); /* PCAP_STATS_EX (third param) means 'extended pcap_stats()' */ return (rpcap_stats_remote(p, &(p->stat), PCAP_STATS_EX)); } #endif /* \ingroup remote_pri_func * * \brief It retrieves network statistics from the other peer. * * This function can be called in two modes: * - PCAP_STATS_STANDARD: if we want just standard statistics (i.e. the pcap_stats() ) * - PCAP_STATS_EX: if we want extended statistics (i.e. the pcap_stats_ex() ) * * This 'mode' parameter is needed because in the standard pcap_stats() the variable that keeps the * statistics is allocated by the user. Unfortunately, this structure has been extended in order * to keep new stats. However, if the user has a smaller structure and it passes it to the pcap_stats, * thid function will try to fill in more data than the size of the structure, so that the application * goes in memory overflow. * So, we need to know it we have to copy just the standard fields, or the extended fields as well. * * In case we want to copy the extended fields as well, the problem of memory overflow does no * longer exist because the structure pcap_stat is no longer allocated by the program; * it is allocated by the library instead. * * \param p: the pcap_t structure related to the current instance. * * \param ps: a 'pcap_stat' structure, needed for compatibility with pcap_stat(), in which * the structure is allocated by the user. In case of pcap_stats_ex, this structure and the * function return value point to the same variable. * * \param mode: one of PCAP_STATS_STANDARD or PCAP_STATS_EX. * * \return The structure that keeps the statistics, or NULL in case of error. * The error string is placed in the pcap_t structure. */ static struct pcap_stat *rpcap_stats_remote(pcap_t *p, struct pcap_stat *ps, int mode) { struct rpcap_header header; /* header of the RPCAP packet */ struct rpcap_stats netstats; /* statistics sent on the network */ uint32 totread = 0; /* number of bytes of the payload read from the socket */ int nread; int retval; /* temp variable which stores functions return value */ struct pcap_md *md; /* structure used when doing a remote live capture */ md = (struct pcap_md *) ((u_char*)p->priv + sizeof(struct pcap_win)); /* * If the capture has still to start, we cannot ask statistics to the other peer, * so we return a fake number */ if (!md->rmt_capstarted) { if (mode == PCAP_STATS_STANDARD) { ps->ps_drop = 0; ps->ps_ifdrop = 0; ps->ps_recv = 0; } else { ps->ps_capt = 0; ps->ps_drop = 0; ps->ps_ifdrop = 0; ps->ps_netdrop = 0; ps->ps_recv = 0; ps->ps_sent = 0; } return ps; } rpcap_createhdr(&header, RPCAP_MSG_STATS_REQ, 0, 0); /* Send the PCAP_STATS command */ if (sock_send(md->rmt_sockctrl, (char *)&header, sizeof(struct rpcap_header), p->errbuf, PCAP_ERRBUF_SIZE)) goto error; /* Receive the RPCAP stats reply message */ if (sock_recv(md->rmt_sockctrl, (char *)&header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, p->errbuf, PCAP_ERRBUF_SIZE) == -1) goto error; /* Checks if the message is correct */ retval = rpcap_checkmsg(p->errbuf, md->rmt_sockctrl, &header, RPCAP_MSG_STATS_REPLY, RPCAP_MSG_ERROR, 0); if (retval != RPCAP_MSG_STATS_REPLY) /* the message is not the one expected */ { switch (retval) { case -3: /* Unrecoverable network error */ case -2: /* The other endpoint send a message that is not allowed here */ case -1: /* The other endpoint has a version number that is not compatible with our */ goto error; case RPCAP_MSG_ERROR: /* The other endpoint reported an error */ /* Update totread, since the rpcap_checkmsg() already purged the buffer */ totread = ntohl(header.plen); /* Do nothing; just exit; the error code is already into the errbuf */ goto error; default: pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Internal error"); goto error; } } nread = sock_recv(md->rmt_sockctrl, (char *)&netstats, sizeof(struct rpcap_stats), SOCK_RECEIVEALL_YES, p->errbuf, PCAP_ERRBUF_SIZE); if (nread == -1) goto error; totread += nread; if (mode == PCAP_STATS_STANDARD) { ps->ps_drop = ntohl(netstats.krnldrop); ps->ps_ifdrop = ntohl(netstats.ifdrop); ps->ps_recv = ntohl(netstats.ifrecv); } else { ps->ps_capt = md->TotCapt; ps->ps_drop = ntohl(netstats.krnldrop); ps->ps_ifdrop = ntohl(netstats.ifdrop); ps->ps_netdrop = md->TotNetDrops; ps->ps_recv = ntohl(netstats.ifrecv); ps->ps_sent = ntohl(netstats.svrcapt); } /* Checks if all the data has been read; if not, discard the data in excess */ if (totread != ntohl(header.plen)) { if (sock_discard(md->rmt_sockctrl, ntohl(header.plen) - totread, NULL, 0) == 1) goto error; } return ps; error: if (totread != ntohl(header.plen)) sock_discard(md->rmt_sockctrl, ntohl(header.plen) - totread, NULL, 0); return NULL; } /* \ingroup remote_pri_func * * \brief It opens a remote adapter by opening an RPCAP connection and so on. * * This function does basically the job of pcap_open_live() for a remote interface. * In other words, we have a pcap_read for win32, which reads packets from NPF, * another for LINUX, and so on. Now, we have a pcap_opensource_remote() as well. * The difference, here, is the capture thread does not start until the * pcap_startcapture_remote() is called. * * This is because, in remote capture, we cannot start capturing data as soon ad the * 'open adapter' command is sent. Suppose the remote adapter is already overloaded; * if we start a capture (which, by default, has a NULL filter) the new traffic can * saturate the network. * * Instead, we want to "open" the adapter, then send a "start capture" command only * when we're ready to start the capture. * This funtion does this job: it sends a "open adapter" command (according to the * RPCAP protocol), but it does not start the capture. * * Since the other libpcap functions do not share this way of life, we have to make * some dirty things in order to make everyting working. * * \param fp: A pointer to a pcap_t structure that has been previously created with * \ref pcap_create(). * \param source: see pcap_open(). * \param auth: see pcap_open(). * * \return 0 in case of success, -1 otherwise. In case of success, the pcap_t pointer in fp can be * used as a parameter to the following calls (pcap_compile() and so on). In case of * problems, fp->errbuf contains a text explanation of error. * * \warning In case we call the pcap_compile() and the capture is not started, the filter * will be saved into the pcap_t structure, and it will be sent to the other host later * (when the pcap_startcapture_remote() is called). */ int pcap_opensource_remote(pcap_t *fp, struct pcap_rmtauth *auth) { char host[PCAP_BUF_SIZE], ctrlport[PCAP_BUF_SIZE], iface[PCAP_BUF_SIZE]; char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data to be sent is buffered */ int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ uint32 totread = 0; /* number of bytes of the payload read from the socket */ int nread; int retval; /* store the return value of the functions */ int active = 0; /* '1' if we're in active mode */ /* socket-related variables */ struct addrinfo hints; /* temp, needed to open a socket connection */ struct addrinfo *addrinfo; /* temp, needed to open a socket connection */ SOCKET sockctrl = 0; /* socket descriptor of the control connection */ /* RPCAP-related variables */ struct rpcap_header header; /* header of the RPCAP packet */ struct rpcap_openreply openreply; /* open reply message */ struct pcap_md *md; /* structure used when doing a remote live capture */ md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win)); /* * determine the type of the source (NULL, file, local, remote) * You must have a valid source string even if we're in active mode, because otherwise * the call to the following function will fail. */ if (pcap_parsesrcstr(fp->opt.device, &retval, host, ctrlport, iface, fp->errbuf) == -1) return -1; if (retval != PCAP_SRC_IFREMOTE) { pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE, "This function is able to open only remote interfaces"); return -1; } addrinfo = NULL; /* * Warning: this call can be the first one called by the user. * For this reason, we have to initialize the WinSock support. */ if (sock_init(fp->errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; sockctrl = rpcap_remoteact_getsock(host, &active, fp->errbuf); if (sockctrl == INVALID_SOCKET) return -1; if (!active) { /* * We're not in active mode; let's try to open a new * control connection. */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((ctrlport == NULL) || (ctrlport[0] == 0)) { /* the user chose not to specify the port */ if (sock_initaddress(host, RPCAP_DEFAULT_NETPORT, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; } else { /* the user chose not to specify the port */ if (sock_initaddress(host, ctrlport, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; } if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) goto error; freeaddrinfo(addrinfo); addrinfo = NULL; if (rpcap_sendauth(sockctrl, auth, fp->errbuf) == -1) goto error; } /* * Now it's time to start playing with the RPCAP protocol * RPCAP open command: create the request message */ if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) goto error; rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_OPEN_REQ, 0, (uint32) strlen(iface)); if (sock_bufferize(iface, (int) strlen(iface), sendbuf, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, fp->errbuf, PCAP_ERRBUF_SIZE)) goto error; if (sock_send(sockctrl, sendbuf, sendbufidx, fp->errbuf, PCAP_ERRBUF_SIZE)) goto error; /* Receive the RPCAP open reply message */ if (sock_recv(sockctrl, (char *)&header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) goto error; /* Checks if the message is correct */ retval = rpcap_checkmsg(fp->errbuf, sockctrl, &header, RPCAP_MSG_OPEN_REPLY, RPCAP_MSG_ERROR, 0); if (retval != RPCAP_MSG_OPEN_REPLY) /* the message is not the one expected */ { switch (retval) { case -3: /* Unrecoverable network error */ case -2: /* The other endpoint send a message that is not allowed here */ case -1: /* The other endpoint has a version number that is not compatible with our */ goto error; case RPCAP_MSG_ERROR: /* The other endpoint reported an error */ /* Update totread, since the rpcap_checkmsg() already purged the buffer */ totread = ntohl(header.plen); /* Do nothing; just exit; the error code is already into the errbuf */ goto error; default: pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE, "Internal error"); goto error; } } nread = sock_recv(sockctrl, (char *)&openreply, sizeof(struct rpcap_openreply), SOCK_RECEIVEALL_YES, fp->errbuf, PCAP_ERRBUF_SIZE); if (nread == -1) goto error; totread += nread; /* Set proper fields into the pcap_t struct */ fp->linktype = ntohl(openreply.linktype); fp->tzoff = ntohl(openreply.tzoff); md->rmt_sockctrl = sockctrl; md->rmt_clientside = 1; /* This code is duplicated from the end of this function */ fp->read_op = pcap_read_remote; fp->setfilter_op = pcap_setfilter_remote; fp->getnonblock_op = NULL; /* This is not implemented in remote capture */ fp->setnonblock_op = NULL; /* This is not implemented in remote capture */ fp->stats_op = pcap_stats_remote; #ifdef _WIN32 fp->stats_ex_op = pcap_stats_ex_remote; #endif fp->cleanup_op = pcap_cleanup_remote; /* Checks if all the data has been read; if not, discard the data in excess */ if (totread != ntohl(header.plen)) { if (sock_discard(sockctrl, ntohl(header.plen) - totread, NULL, 0) == 1) goto error; } return 0; error: /* * When the connection has been established, we have to close it. So, at the * beginning of this function, if an error occur we return immediately with * a return NULL; when the connection is established, we have to come here * ('goto error;') in order to close everything properly. * * Checks if all the data has been read; if not, discard the data in excess */ if (totread != ntohl(header.plen)) sock_discard(sockctrl, ntohl(header.plen) - totread, NULL, 0); if (addrinfo) freeaddrinfo(addrinfo); if (!active) sock_close(sockctrl, NULL, 0); return -1; } /* \ingroup remote_pri_func * * \brief It starts a remote capture. * * This function is requires since the RPCAP protocol decouples the 'open' from the * 'start capture' functions. * This function takes all the parameters needed (which have been stored into the pcap_t structure) * and sends them to the server. * If everything is fine, it creates a new child thread that reads data from the network * and puts data it into the user buffer. * The pcap_read() will read data from the user buffer, as usual. * * The remote capture acts like a new "kernel", which puts packets directly into * the buffer pointed by pcap_t. * In fact, this function does not rely on a kernel that reads packets and put them * into the user buffer; it has to do that on its own. * * \param fp: the pcap_t descriptor of the device currently open. * * \return '0' if everything is fine, '-1' otherwise. The error message (if one) * is returned into the 'errbuf' field of the pcap_t structure. */ int pcap_startcapture_remote(pcap_t *fp) { char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data to be sent is buffered */ int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ char portdata[PCAP_BUF_SIZE]; /* temp variable needed to keep the network port for the the data connection */ uint32 totread = 0; /* number of bytes of the payload read from the socket */ int nread; int retval; /* store the return value of the functions */ int active = 0; /* '1' if we're in active mode */ struct activehosts *temp; /* temp var needed to scan the host list chain, to detect if we're in active mode */ char host[INET6_ADDRSTRLEN + 1]; /* numeric name of the other host */ /* socket-related variables*/ struct addrinfo hints; /* temp, needed to open a socket connection */ struct addrinfo *addrinfo; /* temp, needed to open a socket connection */ SOCKET sockdata = 0; /* socket descriptor of the data connection */ struct sockaddr_storage saddr; /* temp, needed to retrieve the network data port chosen on the local machine */ socklen_t saddrlen; /* temp, needed to retrieve the network data port chosen on the local machine */ int ai_family; /* temp, keeps the address family used by the control connection */ /* RPCAP-related variables*/ struct rpcap_header header; /* header of the RPCAP packet */ struct rpcap_startcapreq *startcapreq; /* start capture request message */ struct rpcap_startcapreply startcapreply; /* start capture reply message */ /* Variables related to the buffer setting */ int res, itemp; int sockbufsize = 0; struct pcap_md *md; /* structure used when doing a remote live capture */ md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win)); /* * Let's check if sampling has been required. * If so, let's set it first */ if (pcap_setsampling_remote(fp) != 0) return -1; /* detect if we're in active mode */ temp = activeHosts; while (temp) { if (temp->sockctrl == md->rmt_sockctrl) { active = 1; break; } temp = temp->next; } addrinfo = NULL; /* * Gets the complete sockaddr structure used in the ctrl connection * This is needed to get the address family of the control socket * Tip: I cannot save the ai_family of the ctrl sock in the pcap_t struct, * since the ctrl socket can already be open in case of active mode; * so I would have to call getpeername() anyway */ saddrlen = sizeof(struct sockaddr_storage); if (getpeername(md->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) { sock_geterror("getsockname(): ", fp->errbuf, PCAP_ERRBUF_SIZE); goto error; } ai_family = ((struct sockaddr_storage *) &saddr)->ss_family; /* Get the numeric address of the remote host we are connected to */ if (getnameinfo((struct sockaddr *) &saddr, saddrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST)) { sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE); goto error; } /* * Data connection is opened by the server toward the client if: * - we're using TCP, and the user wants us to be in active mode * - we're using UDP */ if ((active) || (md->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)) { /* * We have to create a new socket to receive packets * We have to do that immediately, since we have to tell the other * end which network port we picked up */ memset(&hints, 0, sizeof(struct addrinfo)); /* TEMP addrinfo is NULL in case of active */ hints.ai_family = ai_family; /* Use the same address family of the control socket */ hints.ai_socktype = (md->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) ? SOCK_DGRAM : SOCK_STREAM; hints.ai_flags = AI_PASSIVE; /* Data connection is opened by the server toward the client */ /* Let's the server pick up a free network port for us */ if (sock_initaddress(NULL, "0", &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) goto error; if ((sockdata = sock_open(addrinfo, SOCKOPEN_SERVER, 1 /* max 1 connection in queue */, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) goto error; /* addrinfo is no longer used */ freeaddrinfo(addrinfo); addrinfo = NULL; /* get the complete sockaddr structure used in the data connection */ saddrlen = sizeof(struct sockaddr_storage); if (getsockname(sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1) { sock_geterror("getsockname(): ", fp->errbuf, PCAP_ERRBUF_SIZE); goto error; } /* Get the local port the system picked up */ if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL, 0, portdata, sizeof(portdata), NI_NUMERICSERV)) { sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE); goto error; } } /* * Now it's time to start playing with the RPCAP protocol * RPCAP start capture command: create the request message */ if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) goto error; rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_STARTCAP_REQ, 0, sizeof(struct rpcap_startcapreq) + sizeof(struct rpcap_filter) + fp->fcode.bf_len * sizeof(struct rpcap_filterbpf_insn)); /* Fill the structure needed to open an adapter remotely */ startcapreq = (struct rpcap_startcapreq *) &sendbuf[sendbufidx]; if (sock_bufferize(NULL, sizeof(struct rpcap_startcapreq), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) goto error; memset(startcapreq, 0, sizeof(struct rpcap_startcapreq)); /* By default, apply half the timeout on one side, half of the other */ fp->opt.timeout = fp->opt.timeout / 2; startcapreq->read_timeout = htonl(fp->opt.timeout); /* portdata on the openreq is meaningful only if we're in active mode */ if ((active) || (md->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)) { sscanf(portdata, "%d", (int *)&(startcapreq->portdata)); /* cast to avoid a compiler warning */ startcapreq->portdata = htons(startcapreq->portdata); } startcapreq->snaplen = htonl(fp->snapshot); startcapreq->flags = 0; if (md->rmt_flags & PCAP_OPENFLAG_PROMISCUOUS) startcapreq->flags |= RPCAP_STARTCAPREQ_FLAG_PROMISC; if (md->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) startcapreq->flags |= RPCAP_STARTCAPREQ_FLAG_DGRAM; if (active) startcapreq->flags |= RPCAP_STARTCAPREQ_FLAG_SERVEROPEN; startcapreq->flags = htons(startcapreq->flags); /* Pack the capture filter */ if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, &fp->fcode)) goto error; if (sock_send(md->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf, PCAP_ERRBUF_SIZE)) goto error; /* Receive the RPCAP start capture reply message */ if (sock_recv(md->rmt_sockctrl, (char *)&header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) goto error; /* Checks if the message is correct */ retval = rpcap_checkmsg(fp->errbuf, md->rmt_sockctrl, &header, RPCAP_MSG_STARTCAP_REPLY, RPCAP_MSG_ERROR, 0); if (retval != RPCAP_MSG_STARTCAP_REPLY) /* the message is not the one expected */ { switch (retval) { case -3: /* Unrecoverable network error */ case -2: /* The other endpoint send a message that is not allowed here */ case -1: /* The other endpoint has a version number that is not compatible with our */ goto error; case RPCAP_MSG_ERROR: /* The other endpoint reported an error */ /* Update totread, since the rpcap_checkmsg() already purged the buffer */ totread = ntohl(header.plen); /* Do nothing; just exit; the error code is already into the errbuf */ goto error; default: pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE, "Internal error"); goto error; } } nread = sock_recv(md->rmt_sockctrl, (char *)&startcapreply, sizeof(struct rpcap_startcapreply), SOCK_RECEIVEALL_YES, fp->errbuf, PCAP_ERRBUF_SIZE); if (nread == -1) goto error; totread += nread; /* * In case of UDP data stream, the connection is always opened by the daemon * So, this case is already covered by the code above. * Now, we have still to handle TCP connections, because: * - if we're in active mode, we have to wait for a remote connection * - if we're in passive more, we have to start a connection * * We have to do he job in two steps because in case we're opening a TCP connection, we have * to tell the port we're using to the remote side; in case we're accepting a TCP * connection, we have to wait this info from the remote side. */ if (!(md->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)) { if (!active) { memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = ai_family; /* Use the same address family of the control socket */ hints.ai_socktype = (md->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) ? SOCK_DGRAM : SOCK_STREAM; pcap_snprintf(portdata, PCAP_BUF_SIZE, "%d", ntohs(startcapreply.portdata)); /* Let's the server pick up a free network port for us */ if (sock_initaddress(host, portdata, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) goto error; if ((sockdata = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) goto error; /* addrinfo is no longer used */ freeaddrinfo(addrinfo); addrinfo = NULL; } else { SOCKET socktemp; /* We need another socket, since we're going to accept() a connection */ /* Connection creation */ saddrlen = sizeof(struct sockaddr_storage); socktemp = accept(sockdata, (struct sockaddr *) &saddr, &saddrlen); if (socktemp == -1) { sock_geterror("accept(): ", fp->errbuf, PCAP_ERRBUF_SIZE); goto error; } /* Now that I accepted the connection, the server socket is no longer needed */ sock_close(sockdata, fp->errbuf, PCAP_ERRBUF_SIZE); sockdata = socktemp; } } /* Let's save the socket of the data connection */ md->rmt_sockdata = sockdata; /* Allocates WinPcap/libpcap user buffer, which is a socket buffer in case of a remote capture */ /* It has the same size of the one used on the other side of the connection */ fp->bufsize = ntohl(startcapreply.bufsize); /* Let's get the actual size of the socket buffer */ itemp = sizeof(sockbufsize); res = getsockopt(sockdata, SOL_SOCKET, SO_RCVBUF, (char *)&sockbufsize, &itemp); if (res == -1) { sock_geterror("pcap_startcapture_remote()", fp->errbuf, PCAP_ERRBUF_SIZE); SOCK_ASSERT(fp->errbuf, 1); } /* * Warning: on some kernels (e.g. Linux), the size of the user buffer does not take * into account the pcap_header and such, and it is set equal to the snaplen. * In my view, this is wrong (the meaning of the bufsize became a bit strange). * So, here bufsize is the whole size of the user buffer. * In case the bufsize returned is too small, let's adjust it accordingly. */ if (fp->bufsize <= (u_int) fp->snapshot) fp->bufsize += sizeof(struct pcap_pkthdr); /* if the current socket buffer is smaller than the desired one */ if ((u_int) sockbufsize < fp->bufsize) { /* Loop until the buffer size is OK or the original socket buffer size is larger than this one */ while (1) { res = setsockopt(sockdata, SOL_SOCKET, SO_RCVBUF, (char *)&(fp->bufsize), sizeof(fp->bufsize)); if (res == 0) break; /* * If something goes wrong, half the buffer size (checking that it does not become smaller than * the current one) */ fp->bufsize /= 2; if ((u_int) sockbufsize >= fp->bufsize) { fp->bufsize = sockbufsize; break; } } } /* * Let's allocate the packet; this is required in order to put the packet somewhere when * extracting data from the socket * Since buffering has already been done in the socket buffer, here we need just a buffer, * whose size is equal to the pcap header plus the snapshot length */ fp->bufsize = fp->snapshot + sizeof(struct pcap_pkthdr); fp->buffer = (u_char *)malloc(fp->bufsize); if (fp->buffer == NULL) { pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); goto error; } /* Checks if all the data has been read; if not, discard the data in excess */ if (totread != ntohl(header.plen)) { if (sock_discard(md->rmt_sockctrl, ntohl(header.plen) - totread, NULL, 0) == 1) goto error; } /* * In case the user does not want to capture RPCAP packets, let's update the filter * We have to update it here (instead of sending it into the 'StartCapture' message * because when we generate the 'start capture' we do not know (yet) all the ports * we're currently using. */ if (md->rmt_flags & PCAP_OPENFLAG_NOCAPTURE_RPCAP) { struct bpf_program fcode; if (pcap_createfilter_norpcappkt(fp, &fcode) == -1) goto error; /* We cannot use 'pcap_setfilter_remote' because formally the capture has not been started yet */ /* (the 'fp->rmt_capstarted' variable will be updated some lines below) */ if (pcap_updatefilter_remote(fp, &fcode) == -1) goto error; pcap_freecode(&fcode); } md->rmt_capstarted = 1; return 0; error: /* * When the connection has been established, we have to close it. So, at the * beginning of this function, if an error occur we return immediately with * a return NULL; when the connection is established, we have to come here * ('goto error;') in order to close everything properly. * * Checks if all the data has been read; if not, discard the data in excess */ if (totread != ntohl(header.plen)) sock_discard(md->rmt_sockctrl, ntohl(header.plen) - totread, NULL, 0); if ((sockdata) && (sockdata != -1)) /* we can be here because sockdata said 'error' */ sock_close(sockdata, NULL, 0); if (!active) sock_close(md->rmt_sockctrl, NULL, 0); /* * We do not have to call pcap_close() here, because this function is always called * by the user in case something bad happens */ // if (fp) // { // pcap_close(fp); // fp= NULL; // } return -1; } /* * \brief Takes a bpf program and sends it to the other host. * * This function can be called in two cases: * - the pcap_startcapture() is called (we have to send the filter along with * the 'start capture' command) * - we want to udpate the filter during a capture (i.e. the pcap_setfilter() * is called when the capture is still on) * * This function serializes the filter into the sending buffer ('sendbuf', passed * as a parameter) and return back. It does not send anything on the network. * * \param fp: the pcap_t descriptor of the device currently opened. * * \param sendbuf: the buffer on which the serialized data has to copied. * * \param sendbufidx: it is used to return the abounf of bytes copied into the buffer. * * \param prog: the bpf program we have to copy. * * \return '0' if everything is fine, '-1' otherwise. The error message (if one) * is returned into the 'errbuf' field of the pcap_t structure. */ static int pcap_pack_bpffilter(pcap_t *fp, char *sendbuf, int *sendbufidx, struct bpf_program *prog) { struct rpcap_filter *filter; struct rpcap_filterbpf_insn *insn; struct bpf_insn *bf_insn; struct bpf_program fake_prog; /* To be used just in case the user forgot to set a filter */ unsigned int i; if (prog->bf_len == 0) /* No filters have been specified; so, let's apply a "fake" filter */ { if (pcap_compile(fp, &fake_prog, NULL /* buffer */, 1, 0) == -1) return -1; prog = &fake_prog; } filter = (struct rpcap_filter *) sendbuf; if (sock_bufferize(NULL, sizeof(struct rpcap_filter), NULL, sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) return -1; filter->filtertype = htons(RPCAP_UPDATEFILTER_BPF); filter->nitems = htonl((int32)prog->bf_len); if (sock_bufferize(NULL, prog->bf_len * sizeof(struct rpcap_filterbpf_insn), NULL, sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) return -1; insn = (struct rpcap_filterbpf_insn *) (filter + 1); bf_insn = prog->bf_insns; for (i = 0; i < prog->bf_len; i++) { insn->code = htons(bf_insn->code); insn->jf = bf_insn->jf; insn->jt = bf_insn->jt; insn->k = htonl(bf_insn->k); insn++; bf_insn++; } return 0; } /* \ingroup remote_pri_func * * \brief Update a filter on a remote host. * * This function is called when the user wants to update a filter. * In case we're capturing from the network, it sends the filter to the other peer. * This function is *not* called automatically when the user calls the pcap_setfilter(). * There will be two cases: * - the capture is already on: in this case, pcap_setfilter() calls pcap_updatefilter_remote() * - the capture has not started yet: in this case, pcap_setfilter() stores the filter into * the pcap_t structure, and then the filter is sent with the pcap_startcap(). * * Parameters and return values are exactly the same of the pcap_setfilter(). * * \warning This function *does not* clear the packet currently into the buffers. Therefore, * the user has to expect to receive some packets that are related to the previous filter. * If you want to discard all the packets before applying a new filter, you have to close * the current capture session and start a new one. */ static int pcap_updatefilter_remote(pcap_t *fp, struct bpf_program *prog) { int retval; /* general variable used to keep the return value of other functions */ char sendbuf[RPCAP_NETBUF_SIZE];/* temporary buffer in which data to be sent is buffered */ int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ struct rpcap_header header; /* To keep the reply message */ struct pcap_md *md; /* structure used when doing a remote live capture */ md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win)); if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) return -1; rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_UPDATEFILTER_REQ, 0, sizeof(struct rpcap_filter) + prog->bf_len * sizeof(struct rpcap_filterbpf_insn)); if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, prog)) return -1; if (sock_send(md->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf, PCAP_ERRBUF_SIZE)) return -1; /* Waits for the answer */ if (sock_recv(md->rmt_sockctrl, (char *)&header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; /* Checks if the message is correct */ retval = rpcap_checkmsg(fp->errbuf, md->rmt_sockctrl, &header, RPCAP_MSG_UPDATEFILTER_REPLY, 0); if (retval != RPCAP_MSG_UPDATEFILTER_REPLY) /* the message is not the one expected */ { switch (retval) { case -3: /* Unrecoverable network error */ case -2: /* The other endpoint sent a message that is not allowed here */ case -1: /* The other endpoint has a version number that is not compatible with our */ /* Do nothing; just exit from here; the error code is already into the errbuf */ return -1; default: SOCK_ASSERT("Internal error", 0); return -1; } } if (ntohl(header.plen) != 0) /* the message has an unexpected size */ { if (sock_discard(md->rmt_sockctrl, ntohl(header.plen), fp->errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; } return 0; } /* * \ingroup remote_pri_func * * \brief Send a filter to a remote host. * * This function is called when the user wants to set a filter. * In case we're capturing from the network, it sends the filter to the other peer. * This function is called automatically when the user calls the pcap_setfilter(). * * Parameters and return values are exactly the same of the pcap_setfilter(). */ static int pcap_setfilter_remote(pcap_t *fp, struct bpf_program *prog) { struct pcap_md *md; /* structure used when doing a remote live capture */ md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win)); if (!md->rmt_capstarted) { /* copy filter into the pcap_t structure */ if (install_bpf_program(fp, prog) == -1) return -1; return 0; } /* we have to update a filter during run-time */ if (pcap_updatefilter_remote(fp, prog)) return -1; return 0; } /* * \ingroup remote_pri_func * * \brief Update the current filter in order not to capture rpcap packets. * * This function is called *only* when the user wants exclude RPCAP packets * related to the current session from the captured packets. * * \return '0' if everything is fine, '-1' otherwise. The error message (if one) * is returned into the 'errbuf' field of the pcap_t structure. */ static int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog) { int RetVal = 0; struct pcap_md *md; /* structure used when doing a remote live capture */ md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win)); /* We do not want to capture our RPCAP traffic. So, let's update the filter */ if (md->rmt_flags & PCAP_OPENFLAG_NOCAPTURE_RPCAP) { struct sockaddr_storage saddr; /* temp, needed to retrieve the network data port chosen on the local machine */ socklen_t saddrlen; /* temp, needed to retrieve the network data port chosen on the local machine */ char myaddress[128]; char myctrlport[128]; char mydataport[128]; char peeraddress[128]; char peerctrlport[128]; char *newfilter; const int newstringsize = 1024; size_t currentfiltersize; /* Get the name/port of the other peer */ saddrlen = sizeof(struct sockaddr_storage); if (getpeername(md->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) { sock_geterror("getpeername(): ", fp->errbuf, PCAP_ERRBUF_SIZE); return -1; } if (getnameinfo((struct sockaddr *) &saddr, saddrlen, peeraddress, sizeof(peeraddress), peerctrlport, sizeof(peerctrlport), NI_NUMERICHOST | NI_NUMERICSERV)) { sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE); return -1; } /* We cannot check the data port, because this is available only in case of TCP sockets */ /* Get the name/port of the current host */ if (getsockname(md->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) { sock_geterror("getsockname(): ", fp->errbuf, PCAP_ERRBUF_SIZE); return -1; } /* Get the local port the system picked up */ if (getnameinfo((struct sockaddr *) &saddr, saddrlen, myaddress, sizeof(myaddress), myctrlport, sizeof(myctrlport), NI_NUMERICHOST | NI_NUMERICSERV)) { sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE); return -1; } /* Let's now check the data port */ if (getsockname(md->rmt_sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1) { sock_geterror("getsockname(): ", fp->errbuf, PCAP_ERRBUF_SIZE); return -1; } /* Get the local port the system picked up */ if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL, 0, mydataport, sizeof(mydataport), NI_NUMERICSERV)) { sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE); return -1; } currentfiltersize = strlen(md->currentfilter); newfilter = (char *)malloc(currentfiltersize + newstringsize + 1); if (currentfiltersize) { pcap_snprintf(newfilter, currentfiltersize + newstringsize, "(%s) and not (host %s and host %s and port %s and port %s) and not (host %s and host %s and port %s)", md->currentfilter, myaddress, peeraddress, myctrlport, peerctrlport, myaddress, peeraddress, mydataport); } else { pcap_snprintf(newfilter, currentfiltersize + newstringsize, "not (host %s and host %s and port %s and port %s) and not (host %s and host %s and port %s)", myaddress, peeraddress, myctrlport, peerctrlport, myaddress, peeraddress, mydataport); } newfilter[currentfiltersize + newstringsize] = 0; /* This is only an hack to make the pcap_compile() working properly */ md->rmt_clientside = 0; if (pcap_compile(fp, prog, newfilter, 1, 0) == -1) RetVal = -1; /* This is only an hack to make the pcap_compile() working properly */ md->rmt_clientside = 1; free(newfilter); } return RetVal; } /* * \ingroup remote_pri_func * * \brief Set sampling parameters in the remote host. * * This function is called when the user wants to set activate sampling on the remote host. * * Sampling parameters are defined into the 'pcap_t' structure. * * \param p: the pcap_t descriptor of the device currently opened. * * \return '0' if everything is OK, '-1' is something goes wrong. The error message is returned * in the 'errbuf' member of the pcap_t structure. */ static int pcap_setsampling_remote(pcap_t *p) { int retval; /* general variable used to keep the return value of other functions */ char sendbuf[RPCAP_NETBUF_SIZE];/* temporary buffer in which data to be sent is buffered */ int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ struct rpcap_header header; /* To keep the reply message */ struct rpcap_sampling *sampling_pars; /* Structure that is needed to send sampling parameters to the remote host */ struct pcap_md *md; /* structure used when doing a remote live capture */ md = (struct pcap_md *) ((u_char*)p->priv + sizeof(struct pcap_win)); /* If no samping is requested, return 'ok' */ if (md->rmt_samp.method == PCAP_SAMP_NOSAMP) return 0; if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, p->errbuf, PCAP_ERRBUF_SIZE)) return -1; rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_SETSAMPLING_REQ, 0, sizeof(struct rpcap_sampling)); /* Fill the structure needed to open an adapter remotely */ sampling_pars = (struct rpcap_sampling *) &sendbuf[sendbufidx]; if (sock_bufferize(NULL, sizeof(struct rpcap_sampling), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, p->errbuf, PCAP_ERRBUF_SIZE)) return -1; memset(sampling_pars, 0, sizeof(struct rpcap_sampling)); sampling_pars->method = md->rmt_samp.method; sampling_pars->value = htonl(md->rmt_samp.value); if (sock_send(md->rmt_sockctrl, sendbuf, sendbufidx, p->errbuf, PCAP_ERRBUF_SIZE)) return -1; /* Waits for the answer */ if (sock_recv(md->rmt_sockctrl, (char *)&header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, p->errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; /* Checks if the message is correct */ retval = rpcap_checkmsg(p->errbuf, md->rmt_sockctrl, &header, RPCAP_MSG_SETSAMPLING_REPLY, 0); if (retval != RPCAP_MSG_SETSAMPLING_REPLY) /* the message is not the one expected */ { switch (retval) { case -3: /* Unrecoverable network error */ case -2: /* The other endpoint sent a message that is not allowed here */ case -1: /* The other endpoint has a version number that is not compatible with our */ case RPCAP_MSG_ERROR: /* Do nothing; just exit from here; the error code is already into the errbuf */ return -1; default: SOCK_ASSERT("Internal error", 0); return -1; } } if (ntohl(header.plen) != 0) /* the message has an unexpected size */ { if (sock_discard(md->rmt_sockctrl, ntohl(header.plen), p->errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; } return 0; } /********************************************************* * * * Miscellaneous functions * * * *********************************************************/ /* \ingroup remote_pri_func * \brief It sends a RPCAP error to the other peer. * * This function has to be called when the main program detects an error. This function * will send on the other peer the 'buffer' specified by the user. * This function *does not* request a RPCAP CLOSE connection. A CLOSE command must be sent * explicitly by the program, since we do not know it the error can be recovered in some * way or it is a non-recoverable one. * * \param sock: the socket we are currently using. * * \param error: an user-allocated (and '0' terminated) buffer that contains the error * description that has to be transmitted on the other peer. The error message cannot * be longer than PCAP_ERRBUF_SIZE. * * \param errcode: a integer which tells the other party the type of error we had; * currently is is not too much used. * * \param errbuf: a pointer to a user-allocated buffer (of size PCAP_ERRBUF_SIZE) * that will contain the error message (in case there is one). It could be network problem. * * \return '0' if everything is fine, '-1' if some errors occurred. The error message is returned * in the 'errbuf' variable. */ int rpcap_senderror(SOCKET sock, char *error, unsigned short errcode, char *errbuf) { char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data to be sent is buffered */ int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ uint16 length; length = (uint16)strlen(error); if (length > PCAP_ERRBUF_SIZE) length = PCAP_ERRBUF_SIZE; rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_ERROR, errcode, length); if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE)) return -1; if (sock_bufferize(error, length, sendbuf, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE)) return -1; if (sock_send(sock, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE)) return -1; return 0; } /* \ingroup remote_pri_func * \brief Sends the authentication message. * * It sends the authentication parameters on the control socket. * This function is required in order to open the connection with the other end party. * * \param sock: the socket we are currently using. * * \param auth: authentication parameters that have to be sent. * * \param errbuf: a pointer to a user-allocated buffer (of size PCAP_ERRBUF_SIZE) * that will contain the error message (in case there is one). It could be network problem * of the fact that the authorization failed. * * \return '0' if everything is fine, '-1' if some errors occurred. The error message is returned * in the 'errbuf' variable. * The error message could be also 'the authentication failed'. */ int rpcap_sendauth(SOCKET sock, struct pcap_rmtauth *auth, char *errbuf) { char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data that has to be sent is buffered */ int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ uint16 length; /* length of the payload of this message */ struct rpcap_auth *rpauth; uint16 auth_type; struct rpcap_header header; int retval; /* temp variable which stores functions return value */ if (auth) { auth_type = auth->type; switch (auth->type) { case RPCAP_RMTAUTH_NULL: length = sizeof(struct rpcap_auth); break; case RPCAP_RMTAUTH_PWD: length = sizeof(struct rpcap_auth); if (auth->username) length += (uint16) strlen(auth->username); if (auth->password) length += (uint16) strlen(auth->password); break; default: pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication type not recognized."); return -1; } } else { auth_type = RPCAP_RMTAUTH_NULL; length = sizeof(struct rpcap_auth); } if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE)) return -1; rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_AUTH_REQ, 0, length); rpauth = (struct rpcap_auth *) &sendbuf[sendbufidx]; if (sock_bufferize(NULL, sizeof(struct rpcap_auth), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE)) return -1; memset(rpauth, 0, sizeof(struct rpcap_auth)); rpauth->type = htons(auth_type); if (auth_type == RPCAP_RMTAUTH_PWD) { if (auth->username) rpauth->slen1 = (uint16) strlen(auth->username); else rpauth->slen1 = 0; if (sock_bufferize(auth->username, rpauth->slen1, sendbuf, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE)) return -1; if (auth->password) rpauth->slen2 = (uint16) strlen(auth->password); else rpauth->slen2 = 0; if (sock_bufferize(auth->password, rpauth->slen2, sendbuf, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE)) return -1; rpauth->slen1 = htons(rpauth->slen1); rpauth->slen2 = htons(rpauth->slen2); } if (sock_send(sock, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE)) return -1; if (sock_recv(sock, (char *)&header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; retval = rpcap_checkmsg(errbuf, sock, &header, RPCAP_MSG_AUTH_REPLY, RPCAP_MSG_ERROR, 0); if (retval != RPCAP_MSG_AUTH_REPLY) /* the message is not the one expected */ { switch (retval) { case -3: /* Unrecoverable network error */ case -2: /* The other endpoint sent a message that is not allowed here */ case -1: /* The other endpoint has a version number that is not compatible with our */ /* Do nothing; just exit from here; the error code is already into the errbuf */ return -1; case RPCAP_MSG_ERROR: return -1; default: SOCK_ASSERT("Internal error", 0); return -1; } } if (ntohl(header.plen)) { if (sock_discard(sock, ntohl(header.plen), errbuf, PCAP_ERRBUF_SIZE)) return -1; } return 0; } /* \ingroup remote_pri_func * \brief Creates a structure of type rpcap_header. * * This function is provided just because the creation of an rpcap header is quite a common * task. It accepts all the values that appears into an rpcap_header, and it puts them in * place using the proper hton() calls. * * \param header: a pointer to a user-allocated buffer which will contain the serialized * header, ready to be sent on the network. * * \param type: a value (in the host by order) which will be placed into the header.type * field and that represents the type of the current message. * * \param value: a value (in the host by order) which will be placed into the header.value * field and that has a message-dependent meaning. * * \param length: a value (in the host by order) which will be placed into the header.length * field and that represents the payload length of the message. * * \return Nothing. The serialized header is returned into the 'header' variable. */ void rpcap_createhdr(struct rpcap_header *header, uint8 type, uint16 value, uint32 length) { memset(header, 0, sizeof(struct rpcap_header)); header->ver = RPCAP_VERSION; header->type = type; header->value = htons(value); header->plen = htonl(length); } /* ingroup remote_pri_func * \brief Checks if the header of the received message is correct. * * This function is a way to easily check if the message received, in a certain * state of the RPCAP protocol Finite State Machine, is valid. This function accepts, * as a parameter, the list of message types that are allowed in a certain situation, * and it returns the one which occurs. * * \param errbuf: a pointer to a user-allocated buffer (of size PCAP_ERRBUF_SIZE) * that will contain the error message (in case there is one). It could be either problem * occurred inside this function (e.g. a network problem in case it tries to send an * error on the other peer and the send() call fails), an error message which has been * sent to us from the other party, or a version error (the message receive has a version * number that is incompatible with our). * * \param sock: the socket that has to be used to receive data. This function can * read data from socket in case the version contained into the message is not compatible * with our. In that case, all the message is purged from the socket, so that the following * recv() calls will return a new message. * * \param header: a pointer to and 'rpcap_header' structure that keeps the data received from * the network (still in network byte order) and that has to be checked. * * \param first: this function has a variable number of parameters. From this point on, * all the messages that are valid in this context must be passed as parameters. * The message type list must be terminated with a '0' value, the null message type, * which means 'no more types to check'. The RPCAP protocol does not define anything with * message type equal to zero, so there is no ambiguity in using this value as a list terminator. * * \return The message type of the message that has been detected. In case of errors (e.g. the * header contains a type that is not listed among the allowed types), this function will * return the following codes: * - (-1) if the version is incompatible. * - (-2) if the code is not among the one listed into the parameters list * - (-3) if a network error (connection reset, ...) * - RPCAP_MSG_ERROR if the message is an error message (it follow that the RPCAP_MSG_ERROR * could not be present in the allowed message-types list, because this function checks * for errors anyway) * * In case either the version is incompatible or nothing matches (i.e. it returns '-1' or '-2'), * it discards the message body (i.e. it reads the remaining part of the message from the * network and it discards it) so that the application is ready to receive a new message. */ int rpcap_checkmsg(char *errbuf, SOCKET sock, struct rpcap_header *header, uint8 first, ...) { va_list ap; uint8 type; int32 len; va_start(ap, first); /* Check if the present version of the protocol can handle this message */ if (rpcap_checkver(sock, header, errbuf)) { SOCK_ASSERT(errbuf, 1); va_end(ap); return -1; } type = first; while (type != 0) { /* * The message matches with one of the types listed * There is no need of conversions since both values are uint8 * * Check if the other side reported an error. * If yes, it retrieves it and it returns it back to the caller */ if (header->type == RPCAP_MSG_ERROR) { len = ntohl(header->plen); if (len >= PCAP_ERRBUF_SIZE) { if (sock_recv(sock, errbuf, PCAP_ERRBUF_SIZE - 1, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE)) return -3; sock_discard(sock, len - (PCAP_ERRBUF_SIZE - 1), NULL, 0); /* Put '\0' at the end of the string */ errbuf[PCAP_ERRBUF_SIZE - 1] = 0; } else { if (sock_recv(sock, errbuf, len, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1) return -3; /* Put '\0' at the end of the string */ errbuf[len] = 0; } va_end(ap); return header->type; } if (header->type == type) { va_end(ap); return header->type; } /* get next argument */ type = va_arg(ap, int); } /* we already have an error, so please discard this one */ sock_discard(sock, ntohl(header->plen), NULL, 0); pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The other endpoint sent a message that is not allowed here."); SOCK_ASSERT(errbuf, 1); va_end(ap); return -2; } /* \ingroup remote_pri_func * \brief Checks if the version contained into the message is compatible with * the one handled by this implementation. * * Right now, this function does not have any sophisticated task: if the versions * are different, it returns -1 and it discards the message. * It is expected that in the future this message will become more complex. * * \param sock: the socket that has to be used to receive data. This function can * read data from socket in case the version contained into the message is not compatible * with our. In that case, all the message is purged from the socket, so that the following * recv() calls will return a new (clean) message. * * \param header: a pointer to and 'rpcap_header' structure that keeps the data received from * the network (still in network byte order) and that has to be checked. * * \param errbuf: a pointer to a user-allocated buffer (of size PCAP_ERRBUF_SIZE) * that will contain the error message (in case there is one). The error message is * "incompatible version". * * \return '0' if everything is fine, '-1' if some errors occurred. The error message is returned * in the 'errbuf' variable. */ static int rpcap_checkver(SOCKET sock, struct rpcap_header *header, char *errbuf) { /* * This is a sample function. * * In the real world, you have to check at the type code, * and decide accordingly. */ if (header->ver != RPCAP_VERSION) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Incompatible version number: message discarded."); /* we already have an error, so please discard this one */ sock_discard(sock, ntohl(header->plen), NULL, 0); return -1; } return 0; } /* \ingroup remote_pri_func * * \brief It returns the socket currently used for this active connection * (active mode only) and provides an indication of whether this connection * is in active mode or not. * * This function is just for internal use; it returns the socket ID of the * active connection currently opened. * * \param host: a string that keeps the host name of the host for which we * want to get the socket ID for that active connection. * * \param isactive: a pointer to an int that is set to 1 if there's an * active connection to that host and 0 otherwise. * * \param errbuf: a pointer to a user-allocated buffer (of size * PCAP_ERRBUF_SIZE) that will contain the error message (in case * there is one). * * \return the socket identifier if everything is fine, '0' if this host * is not in the active host list. An indication of whether this host * is in the active host list is returned into the isactive variable. * It returns 'INVALID_SOCKET' in case of error. The error message is * returned into the errbuf variable. */ SOCKET rpcap_remoteact_getsock(const char *host, int *isactive, char *errbuf) { struct activehosts *temp; /* temp var needed to scan the host list chain */ struct addrinfo hints, *addrinfo, *ai_next; /* temp var needed to translate between hostname to its address */ int retval; /* retrieve the network address corresponding to 'host' */ addrinfo = NULL; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; retval = getaddrinfo(host, "0", &hints, &addrinfo); if (retval != 0) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval)); *isactive = 0; return INVALID_SOCKET; } temp = activeHosts; while (temp) { ai_next = addrinfo; while (ai_next) { if (sock_cmpaddr(&temp->host, (struct sockaddr_storage *) ai_next->ai_addr) == 0) { *isactive = 1; return (temp->sockctrl); } ai_next = ai_next->ai_next; } temp = temp->next; } if (addrinfo) freeaddrinfo(addrinfo); /* * The host for which you want to get the socket ID does not have an * active connection. */ *isactive = 0; return 0; } libpcap-1.8.1/pcap_findalldevs.3pcap0000644000026300017510000001207213003771737015516 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_FINDALLDEVS 3PCAP "7 April 2014" .SH NAME pcap_findalldevs, pcap_freealldevs \- get a list of capture devices, and free that list .SH SYNOPSIS .nf .ft B #include .ft .LP .nf .ft B char errbuf[PCAP_ERRBUF_SIZE]; .ft .LP .ft B int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf); void pcap_freealldevs(pcap_if_t *alldevs); .ft .fi .SH DESCRIPTION .B pcap_findalldevs() constructs a list of network devices that can be opened with .B pcap_create() and .B pcap_activate() or with .BR pcap_open_live() . (Note that there may be network devices that cannot be opened by the process calling .BR pcap_findalldevs() , because, for example, that process does not have sufficient privileges to open them for capturing; if so, those devices will not appear on the list.) If .B pcap_findalldevs() succeeds, the pointer pointed to by .I alldevsp is set to point to the first element of the list, or to .B NULL if no devices were found (this is considered success). Each element of the list is of type .BR pcap_if_t , and has the following members: .RS .TP .B next if not .BR NULL , a pointer to the next element in the list; .B NULL for the last element of the list .TP .B name a pointer to a string giving a name for the device to pass to .B pcap_open_live() .TP .B description if not .BR NULL , a pointer to a string giving a human-readable description of the device .TP .B addresses a pointer to the first element of a list of network addresses for the device, or .B NULL if the device has no addresses .TP .B flags device flags: .RS .TP .B PCAP_IF_LOOPBACK set if the device is a loopback interface .TP .B PCAP_IF_UP set if the device is up .TP .B PCAP_IF_RUNNING set if the device is running .RE .RE .PP Each element of the list of addresses is of type .BR pcap_addr_t , and has the following members: .RS .TP .B next if not .BR NULL , a pointer to the next element in the list; .B NULL for the last element of the list .TP .B addr a pointer to a .B "struct sockaddr" containing an address .TP .B netmask if not .BR NULL , a pointer to a .B "struct sockaddr" that contains the netmask corresponding to the address pointed to by .B addr .TP .B broadaddr if not .BR NULL , a pointer to a .B "struct sockaddr" that contains the broadcast address corresponding to the address pointed to by .BR addr ; may be null if the device doesn't support broadcasts .TP .B dstaddr if not .BR NULL , a pointer to a .B "struct sockaddr" that contains the destination address corresponding to the address pointed to by .BR addr ; may be null if the device isn't a point-to-point interface .RE .PP Note that the addresses in the list of addresses might be IPv4 addresses, IPv6 addresses, or some other type of addresses, so you must check the .B sa_family member of the .B "struct sockaddr" before interpreting the contents of the address; do not assume that the addresses are all IPv4 addresses, or even all IPv4 or IPv6 addresses. IPv4 addresses have the value .BR AF_INET , IPv6 addresses have the value .B AF_INET6 (which older operating systems that don't support IPv6 might not define), and other addresses have other values. Whether other addresses are returned, and what types they might have is platform-dependent. For IPv4 addresses, the .B "struct sockaddr" pointer can be interpreted as if it pointed to a .BR "struct sockaddr_in" ; for IPv6 addresses, it can be interpreted as if it pointed to a .BR "struct sockaddr_in6". .PP The list of devices must be freed with .BR pcap_freealldevs() , which frees the list pointed to by .IR alldevs . .SH RETURN VALUE .B pcap_findalldevs() returns 0 on success and \-1 on failure; as indicated, finding no devices is considered success, rather than failure, so 0 will be returned in that case. If \-1 is returned, .I errbuf is filled in with an appropriate error message. .I errbuf is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), pcap_open_live(3PCAP) libpcap-1.8.1/aclocal.m40000644000026300017510000011020613003771737013126 0ustar mcrmcrdnl Copyright (c) 1995, 1996, 1997, 1998 dnl The Regents of the University of California. All rights reserved. dnl dnl Redistribution and use in source and binary forms, with or without dnl modification, are permitted provided that: (1) source code distributions dnl retain the above copyright notice and this paragraph in its entirety, (2) dnl distributions including binary code include the above copyright notice and dnl this paragraph in its entirety in the documentation or other materials dnl provided with the distribution, and (3) all advertising materials mentioning dnl features or use of this software display the following acknowledgement: dnl ``This product includes software developed by the University of California, dnl Lawrence Berkeley Laboratory and its contributors.'' Neither the name of dnl the University nor the names of its contributors may be used to endorse dnl or promote products derived from this software without specific prior dnl written permission. dnl THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED dnl WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF dnl MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. dnl dnl LBL autoconf macros dnl dnl dnl Do whatever AC_LBL_C_INIT work is necessary before using AC_PROG_CC. dnl dnl It appears that newer versions of autoconf (2.64 and later) will, dnl if you use AC_TRY_COMPILE in a macro, stick AC_PROG_CC at the dnl beginning of the macro, even if the macro itself calls AC_PROG_CC. dnl See the "Prerequisite Macros" and "Expanded Before Required" sections dnl in the Autoconf documentation. dnl dnl This causes a steaming heap of fail in our case, as we were, in dnl AC_LBL_C_INIT, doing the tests we now do in AC_LBL_C_INIT_BEFORE_CC, dnl calling AC_PROG_CC, and then doing the tests we now do in dnl AC_LBL_C_INIT. Now, we run AC_LBL_C_INIT_BEFORE_CC, AC_PROG_CC, dnl and AC_LBL_C_INIT at the top level. dnl AC_DEFUN(AC_LBL_C_INIT_BEFORE_CC, [ AC_BEFORE([$0], [AC_LBL_C_INIT]) AC_BEFORE([$0], [AC_PROG_CC]) AC_BEFORE([$0], [AC_LBL_FIXINCLUDES]) AC_BEFORE([$0], [AC_LBL_DEVEL]) AC_ARG_WITH(gcc, [ --without-gcc don't use gcc]) $1="" if test "${srcdir}" != "." ; then $1="-I\$(srcdir)" fi if test "${CFLAGS+set}" = set; then LBL_CFLAGS="$CFLAGS" fi if test -z "$CC" ; then case "$host_os" in bsdi*) AC_CHECK_PROG(SHLICC2, shlicc2, yes, no) if test $SHLICC2 = yes ; then CC=shlicc2 export CC fi ;; esac fi if test -z "$CC" -a "$with_gcc" = no ; then CC=cc export CC fi ]) dnl dnl Determine which compiler we're using (cc or gcc) dnl If using gcc, determine the version number dnl If using cc: dnl require that it support ansi prototypes dnl use -O (AC_PROG_CC will use -g -O2 on gcc, so we don't need to dnl do that ourselves for gcc) dnl add -g flags, as appropriate dnl explicitly specify /usr/local/include dnl dnl NOTE WELL: with newer versions of autoconf, "gcc" means any compiler dnl that defines __GNUC__, which means clang, for example, counts as "gcc". dnl dnl usage: dnl dnl AC_LBL_C_INIT(copt, incls) dnl dnl results: dnl dnl $1 (copt set) dnl $2 (incls set) dnl CC dnl LDFLAGS dnl LBL_CFLAGS dnl AC_DEFUN(AC_LBL_C_INIT, [ AC_BEFORE([$0], [AC_LBL_FIXINCLUDES]) AC_BEFORE([$0], [AC_LBL_DEVEL]) AC_BEFORE([$0], [AC_LBL_SHLIBS_INIT]) if test "$GCC" = yes ; then # # -Werror forces warnings to be errors. # ac_lbl_cc_force_warning_errors=-Werror # # Try to have the compiler default to hiding symbols, # so that only symbols explicitly exported with # PCAP_API will be visible outside (shared) libraries. # AC_LBL_CHECK_COMPILER_OPT($1, -fvisibility=hidden) else $2="$$2 -I/usr/local/include" LDFLAGS="$LDFLAGS -L/usr/local/lib" case "$host_os" in darwin*) # # This is assumed either to be GCC or clang, both # of which use -Werror to force warnings to be errors. # ac_lbl_cc_force_warning_errors=-Werror # # Try to have the compiler default to hiding symbols, # so that only symbols explicitly exported with # PCAP_API will be visible outside (shared) libraries. # AC_LBL_CHECK_COMPILER_OPT($1, -fvisibility=hidden) ;; hpux*) # # HP C, which is what we presume we're using, doesn't # exit with a non-zero exit status if we hand it an # invalid -W flag, can't be forced to do so even with # +We, and doesn't handle GCC-style -W flags, so we # don't want to try using GCC-style -W flags. # ac_lbl_cc_dont_try_gcc_dashW=yes ;; irix*) # # MIPS C, which is what we presume we're using, doesn't # necessarily exit with a non-zero exit status if we # hand it an invalid -W flag, can't be forced to do # so, and doesn't handle GCC-style -W flags, so we # don't want to try using GCC-style -W flags. # ac_lbl_cc_dont_try_gcc_dashW=yes # # It also, apparently, defaults to "char" being # unsigned, unlike most other C implementations; # I suppose we could say "signed char" whenever # we want to guarantee a signed "char", but let's # just force signed chars. # # -xansi is normally the default, but the # configure script was setting it; perhaps -cckr # was the default in the Old Days. (Then again, # that would probably be for backwards compatibility # in the days when ANSI C was Shiny and New, i.e. # 1989 and the early '90's, so maybe we can just # drop support for those compilers.) # # -g is equivalent to -g2, which turns off # optimization; we choose -g3, which generates # debugging information but doesn't turn off # optimization (even if the optimization would # cause inaccuracies in debugging). # $1="$$1 -xansi -signed -g3" ;; osf*) # # Presumed to be DEC OSF/1, Digital UNIX, or # Tru64 UNIX. # # The DEC C compiler, which is what we presume we're # using, doesn't exit with a non-zero exit status if we # hand it an invalid -W flag, can't be forced to do # so, and doesn't handle GCC-style -W flags, so we # don't want to try using GCC-style -W flags. # ac_lbl_cc_dont_try_gcc_dashW=yes # # -g is equivalent to -g2, which turns off # optimization; we choose -g3, which generates # debugging information but doesn't turn off # optimization (even if the optimization would # cause inaccuracies in debugging). # $1="$$1 -g3" ;; solaris*) # # Assumed to be Sun C, which requires -errwarn to force # warnings to be treated as errors. # ac_lbl_cc_force_warning_errors=-errwarn # # Try to have the compiler default to hiding symbols, # so that only symbols explicitly exported with # PCAP_API will be visible outside (shared) libraries. # AC_LBL_CHECK_COMPILER_OPT($1, -xldscope=hidden) ;; ultrix*) AC_MSG_CHECKING(that Ultrix $CC hacks const in prototypes) AC_CACHE_VAL(ac_cv_lbl_cc_const_proto, AC_TRY_COMPILE( [#include ], [struct a { int b; }; void c(const struct a *)], ac_cv_lbl_cc_const_proto=yes, ac_cv_lbl_cc_const_proto=no)) AC_MSG_RESULT($ac_cv_lbl_cc_const_proto) if test $ac_cv_lbl_cc_const_proto = no ; then AC_DEFINE(const,[], [to handle Ultrix compilers that don't support const in prototypes]) fi ;; esac $1="$$1 -O" fi ]) dnl dnl Check whether, if you pass an unknown warning option to the dnl compiler, it fails or just prints a warning message and succeeds. dnl Set ac_lbl_unknown_warning_option_error to the appropriate flag dnl to force an error if it would otherwise just print a warning message dnl and succeed. dnl AC_DEFUN(AC_LBL_CHECK_UNKNOWN_WARNING_OPTION_ERROR, [ AC_MSG_CHECKING([whether the compiler fails when given an unknown warning option]) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wxyzzy-this-will-never-succeed-xyzzy" AC_TRY_COMPILE( [], [return 0], [ AC_MSG_RESULT([no]) # # We're assuming this is clang, where # -Werror=unknown-warning-option is the appropriate # option to force the compiler to fail. # ac_lbl_unknown_warning_option_error="-Werror=unknown-warning-option" ], [ AC_MSG_RESULT([yes]) ]) CFLAGS="$save_CFLAGS" ]) dnl dnl Check whether the compiler option specified as the second argument dnl is supported by the compiler and, if so, add it to the macro dnl specified as the first argument dnl AC_DEFUN(AC_LBL_CHECK_COMPILER_OPT, [ AC_MSG_CHECKING([whether the compiler supports the $2 option]) save_CFLAGS="$CFLAGS" if expr "x$2" : "x-W.*" >/dev/null then CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error $2" elif expr "x$2" : "x-f.*" >/dev/null then CFLAGS="$CFLAGS -Werror $2" elif expr "x$2" : "x-m.*" >/dev/null then CFLAGS="$CFLAGS -Werror $2" else CFLAGS="$CFLAGS $2" fi AC_TRY_COMPILE( [], [return 0], [ AC_MSG_RESULT([yes]) CFLAGS="$save_CFLAGS" $1="$$1 $2" ], [ AC_MSG_RESULT([no]) CFLAGS="$save_CFLAGS" ]) ]) dnl dnl Check whether the compiler supports an option to generate dnl Makefile-style dependency lines dnl dnl GCC uses -M for this. Non-GCC compilers that support this dnl use a variety of flags, including but not limited to -M. dnl dnl We test whether the flag in question is supported, as older dnl versions of compilers might not support it. dnl dnl We don't try all the possible flags, just in case some flag means dnl "generate dependencies" on one compiler but means something else dnl on another compiler. dnl dnl Most compilers that support this send the output to the standard dnl output by default. IBM's XLC, however, supports -M but sends dnl the output to {sourcefile-basename}.u, and AIX has no /dev/stdout dnl to work around that, so we don't bother with XLC. dnl AC_DEFUN(AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT, [ AC_MSG_CHECKING([whether the compiler supports generating dependencies]) if test "$GCC" = yes ; then # # GCC, or a compiler deemed to be GCC by AC_PROG_CC (even # though it's not); we assume that, in this case, the flag # would be -M. # ac_lbl_dependency_flag="-M" else # # Not GCC or a compiler deemed to be GCC; what platform is # this? (We're assuming that if the compiler isn't GCC # it's the compiler from the vendor of the OS; that won't # necessarily be true for x86 platforms, where it might be # the Intel C compiler.) # case "$host_os" in irix*|osf*|darwin*) # # MIPS C for IRIX, DEC C, and clang all use -M. # ac_lbl_dependency_flag="-M" ;; solaris*) # # Sun C uses -xM. # ac_lbl_dependency_flag="-xM" ;; hpux*) # # HP's older C compilers don't support this. # HP's newer C compilers support this with # either +M or +Make; the older compilers # interpret +M as something completely # different, so we use +Make so we don't # think it works with the older compilers. # ac_lbl_dependency_flag="+Make" ;; *) # # Not one of the above; assume no support for # generating dependencies. # ac_lbl_dependency_flag="" ;; esac fi # # Is ac_lbl_dependency_flag defined and, if so, does the compiler # complain about it? # # Note: clang doesn't seem to exit with an error status when handed # an unknown non-warning error, even if you pass it # -Werror=unknown-warning-option. However, it always supports # -M, so the fact that this test always succeeds with clang # isn't an issue. # if test ! -z "$ac_lbl_dependency_flag"; then AC_LANG_CONFTEST( [AC_LANG_SOURCE([[int main(void) { return 0; }]])]) echo "$CC" $ac_lbl_dependency_flag conftest.c >&5 if "$CC" $ac_lbl_dependency_flag conftest.c >/dev/null 2>&1; then AC_MSG_RESULT([yes, with $ac_lbl_dependency_flag]) DEPENDENCY_CFLAG="$ac_lbl_dependency_flag" MKDEP='${srcdir}/mkdep' else AC_MSG_RESULT([no]) # # We can't run mkdep, so have "make depend" do # nothing. # MKDEP=: fi rm -rf conftest* else AC_MSG_RESULT([no]) # # We can't run mkdep, so have "make depend" do # nothing. # MKDEP=: fi AC_SUBST(DEPENDENCY_CFLAG) AC_SUBST(MKDEP) ]) dnl dnl Determine what options are needed to build a shared library dnl dnl usage: dnl dnl AC_LBL_SHLIBS_INIT dnl dnl results: dnl dnl V_CCOPT (modified to build position-independent code) dnl V_SHLIB_CMD dnl V_SHLIB_OPT dnl V_SONAME_OPT dnl V_RPATH_OPT dnl AC_DEFUN(AC_LBL_SHLIBS_INIT, [AC_PREREQ(2.50) if test "$GCC" = yes ; then # # On platforms where we build a shared library: # # add options to generate position-independent code, # if necessary (it's the default in AIX and Darwin/OS X); # # define option to set the soname of the shared library, # if the OS supports that; # # add options to specify, at link time, a directory to # add to the run-time search path, if that's necessary. # V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-shared" case "$host_os" in aix*) ;; freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*) # # Platforms where the linker is the GNU linker # or accepts command-line arguments like # those the GNU linker accepts. # # Some instruction sets require -fPIC on some # operating systems. Check for them. If you # have a combination that requires it, add it # here. # PIC_OPT=-fpic case "$host_cpu" in sparc64*) case "$host_os" in freebsd*|openbsd*) PIC_OPT=-fPIC ;; esac ;; esac V_CCOPT="$V_CCOPT $PIC_OPT" V_SONAME_OPT="-Wl,-soname," V_RPATH_OPT="-Wl,-rpath," ;; hpux*) V_CCOPT="$V_CCOPT -fpic" # # XXX - this assumes GCC is using the HP linker, # rather than the GNU linker, and that the "+h" # option is used on all HP-UX platforms, both .sl # and .so. # V_SONAME_OPT="-Wl,+h," # # By default, directories specifed with -L # are added to the run-time search path, so # we don't add them in pcap-config. # ;; solaris*) V_CCOPT="$V_CCOPT -fpic" # # XXX - this assumes GCC is using the Sun linker, # rather than the GNU linker. # V_SONAME_OPT="-Wl,-h," V_RPATH_OPT="-Wl,-R," ;; esac else # # Set the appropriate compiler flags and, on platforms # where we build a shared library: # # add options to generate position-independent code, # if necessary (it's the default in Darwin/OS X); # # if we generate ".so" shared libraries, define the # appropriate options for building the shared library; # # add options to specify, at link time, a directory to # add to the run-time search path, if that's necessary. # # Note: spaces after V_SONAME_OPT are significant; on # some platforms the soname is passed with a GCC-like # "-Wl,-soname,{soname}" option, with the soname part # of the option, while on other platforms the C compiler # driver takes it as a regular option with the soname # following the option. The same applies to V_RPATH_OPT. # case "$host_os" in aix*) V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-G -bnoentry -bexpall" ;; freebsd*|netbsd*|openbsd*|dragonfly*|linux*) # # "cc" is GCC. # V_CCOPT="$V_CCOPT -fpic" V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-shared" V_SONAME_OPT="-Wl,-soname," V_RPATH_OPT="-Wl,-rpath," ;; hpux*) V_CCOPT="$V_CCOPT +z" V_SHLIB_CMD="\$(LD)" V_SHLIB_OPT="-b" V_SONAME_OPT="+h " # # By default, directories specifed with -L # are added to the run-time search path, so # we don't add them in pcap-config. # ;; osf*) # # Presumed to be DEC OSF/1, Digital UNIX, or # Tru64 UNIX. # V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-shared" V_SONAME_OPT="-soname " V_RPATH_OPT="-rpath " ;; solaris*) V_CCOPT="$V_CCOPT -Kpic" V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-G" V_SONAME_OPT="-h " V_RPATH_OPT="-R" ;; esac fi ]) # # Try compiling a sample of the type of code that appears in # gencode.c with "inline", "__inline__", and "__inline". # # Autoconf's AC_C_INLINE, at least in autoconf 2.13, isn't good enough, # as it just tests whether a function returning "int" can be inlined; # at least some versions of HP's C compiler can inline that, but can't # inline a function that returns a struct pointer. # # Make sure we use the V_CCOPT flags, because some of those might # disable inlining. # AC_DEFUN(AC_LBL_C_INLINE, [AC_MSG_CHECKING(for inline) save_CFLAGS="$CFLAGS" CFLAGS="$V_CCOPT" AC_CACHE_VAL(ac_cv_lbl_inline, [ ac_cv_lbl_inline="" ac_lbl_cc_inline=no for ac_lbl_inline in inline __inline__ __inline do AC_TRY_COMPILE( [#define inline $ac_lbl_inline static inline struct iltest *foo(void); struct iltest { int iltest1; int iltest2; }; static inline struct iltest * foo() { static struct iltest xxx; return &xxx; }],,ac_lbl_cc_inline=yes,) if test "$ac_lbl_cc_inline" = yes ; then break; fi done if test "$ac_lbl_cc_inline" = yes ; then ac_cv_lbl_inline=$ac_lbl_inline fi]) CFLAGS="$save_CFLAGS" if test ! -z "$ac_cv_lbl_inline" ; then AC_MSG_RESULT($ac_cv_lbl_inline) else AC_MSG_RESULT(no) fi AC_DEFINE_UNQUOTED(inline, $ac_cv_lbl_inline, [Define as token for inline if inlining supported])]) dnl dnl If using gcc, make sure we have ANSI ioctl definitions dnl dnl usage: dnl dnl AC_LBL_FIXINCLUDES dnl AC_DEFUN(AC_LBL_FIXINCLUDES, [if test "$GCC" = yes ; then AC_MSG_CHECKING(for ANSI ioctl definitions) AC_CACHE_VAL(ac_cv_lbl_gcc_fixincludes, AC_TRY_COMPILE( [/* * This generates a "duplicate case value" when fixincludes * has not be run. */ # include # include # include # ifdef HAVE_SYS_IOCCOM_H # include # endif], [switch (0) { case _IO('A', 1):; case _IO('B', 1):; }], ac_cv_lbl_gcc_fixincludes=yes, ac_cv_lbl_gcc_fixincludes=no)) AC_MSG_RESULT($ac_cv_lbl_gcc_fixincludes) if test $ac_cv_lbl_gcc_fixincludes = no ; then # Don't cache failure unset ac_cv_lbl_gcc_fixincludes AC_MSG_ERROR(see the INSTALL for more info) fi fi]) dnl dnl Checks to see if union wait is used with WEXITSTATUS() dnl dnl usage: dnl dnl AC_LBL_UNION_WAIT dnl dnl results: dnl dnl DECLWAITSTATUS (defined) dnl AC_DEFUN(AC_LBL_UNION_WAIT, [AC_MSG_CHECKING(if union wait is used) AC_CACHE_VAL(ac_cv_lbl_union_wait, AC_TRY_COMPILE([ # include # include ], [int status; u_int i = WEXITSTATUS(status); u_int j = waitpid(0, &status, 0);], ac_cv_lbl_union_wait=no, ac_cv_lbl_union_wait=yes)) AC_MSG_RESULT($ac_cv_lbl_union_wait) if test $ac_cv_lbl_union_wait = yes ; then AC_DEFINE(DECLWAITSTATUS,union wait,[type for wait]) else AC_DEFINE(DECLWAITSTATUS,int,[type for wait]) fi]) dnl dnl Checks to see if the sockaddr struct has the 4.4 BSD sa_len member dnl dnl usage: dnl dnl AC_LBL_SOCKADDR_SA_LEN dnl dnl results: dnl dnl HAVE_SOCKADDR_SA_LEN (defined) dnl AC_DEFUN(AC_LBL_SOCKADDR_SA_LEN, [AC_MSG_CHECKING(if sockaddr struct has the sa_len member) AC_CACHE_VAL(ac_cv_lbl_sockaddr_has_sa_len, AC_TRY_COMPILE([ # include # include ], [u_int i = sizeof(((struct sockaddr *)0)->sa_len)], ac_cv_lbl_sockaddr_has_sa_len=yes, ac_cv_lbl_sockaddr_has_sa_len=no)) AC_MSG_RESULT($ac_cv_lbl_sockaddr_has_sa_len) if test $ac_cv_lbl_sockaddr_has_sa_len = yes ; then AC_DEFINE(HAVE_SOCKADDR_SA_LEN,1,[if struct sockaddr has the sa_len member]) fi]) dnl dnl Checks to see if there's a sockaddr_storage structure dnl dnl usage: dnl dnl AC_LBL_SOCKADDR_STORAGE dnl dnl results: dnl dnl HAVE_SOCKADDR_STORAGE (defined) dnl AC_DEFUN(AC_LBL_SOCKADDR_STORAGE, [AC_MSG_CHECKING(if sockaddr_storage struct exists) AC_CACHE_VAL(ac_cv_lbl_has_sockaddr_storage, AC_TRY_COMPILE([ # include # include ], [u_int i = sizeof (struct sockaddr_storage)], ac_cv_lbl_has_sockaddr_storage=yes, ac_cv_lbl_has_sockaddr_storage=no)) AC_MSG_RESULT($ac_cv_lbl_has_sockaddr_storage) if test $ac_cv_lbl_has_sockaddr_storage = yes ; then AC_DEFINE(HAVE_SOCKADDR_STORAGE,1,[if struct sockaddr_storage exists]) fi]) dnl dnl Checks to see if the dl_hp_ppa_info_t struct has the HP-UX 11.00 dnl dl_module_id_1 member dnl dnl usage: dnl dnl AC_LBL_HP_PPA_INFO_T_DL_MODULE_ID_1 dnl dnl results: dnl dnl HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 (defined) dnl dnl NOTE: any compile failure means we conclude that it doesn't have dnl that member, so if we don't have DLPI, don't have a dnl header, or have one that doesn't declare a dl_hp_ppa_info_t type, dnl we conclude it doesn't have that member (which is OK, as either we dnl won't be using code that would use that member, or we wouldn't dnl compile in any case). dnl AC_DEFUN(AC_LBL_HP_PPA_INFO_T_DL_MODULE_ID_1, [AC_MSG_CHECKING(if dl_hp_ppa_info_t struct has dl_module_id_1 member) AC_CACHE_VAL(ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1, AC_TRY_COMPILE([ # include # include # include ], [u_int i = sizeof(((dl_hp_ppa_info_t *)0)->dl_module_id_1)], ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1=yes, ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1=no)) AC_MSG_RESULT($ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1) if test $ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1 = yes ; then AC_DEFINE(HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1,1,[if ppa_info_t_dl_module_id exists]) fi]) dnl dnl Checks to see if -R is used dnl dnl usage: dnl dnl AC_LBL_HAVE_RUN_PATH dnl dnl results: dnl dnl ac_cv_lbl_have_run_path (yes or no) dnl AC_DEFUN(AC_LBL_HAVE_RUN_PATH, [AC_MSG_CHECKING(for ${CC-cc} -R) AC_CACHE_VAL(ac_cv_lbl_have_run_path, [echo 'main(){}' > conftest.c ${CC-cc} -o conftest conftest.c -R/a1/b2/c3 >conftest.out 2>&1 if test ! -s conftest.out ; then ac_cv_lbl_have_run_path=yes else ac_cv_lbl_have_run_path=no fi rm -f -r conftest*]) AC_MSG_RESULT($ac_cv_lbl_have_run_path) ]) dnl dnl Checks to see if unaligned memory accesses fail dnl dnl usage: dnl dnl AC_LBL_UNALIGNED_ACCESS dnl dnl results: dnl dnl LBL_ALIGN (DEFINED) dnl AC_DEFUN(AC_LBL_UNALIGNED_ACCESS, [AC_MSG_CHECKING(if unaligned accesses fail) AC_CACHE_VAL(ac_cv_lbl_unaligned_fail, [case "$host_cpu" in # # These are CPU types where: # # the CPU faults on an unaligned access, but at least some # OSes that support that CPU catch the fault and simulate # the unaligned access (e.g., Alpha/{Digital,Tru64} UNIX) - # the simulation is slow, so we don't want to use it; # # the CPU, I infer (from the old # # XXX: should also check that they don't do weird things (like on arm) # # comment) doesn't fault on unaligned accesses, but doesn't # do a normal unaligned fetch, either (e.g., presumably, ARM); # # for whatever reason, the test program doesn't work # (this has been claimed to be the case for several of those # CPUs - I don't know what the problem is; the problem # was reported as "the test program dumps core" for SuperH, # but that's what the test program is *supposed* to do - # it dumps core before it writes anything, so the test # for an empty output file should find an empty output # file and conclude that unaligned accesses don't work). # # This run-time test won't work if you're cross-compiling, so # in order to support cross-compiling for a particular CPU, # we have to wire in the list of CPU types anyway, as far as # I know, so perhaps we should just have a set of CPUs on # which we know it doesn't work, a set of CPUs on which we # know it does work, and have the script just fail on other # cpu types and update it when such a failure occurs. # alpha*|arm*|bfin*|hp*|mips*|sh*|sparc*|ia64|nv1) ac_cv_lbl_unaligned_fail=yes ;; *) cat >conftest.c < # include # include unsigned char a[[5]] = { 1, 2, 3, 4, 5 }; main() { unsigned int i; pid_t pid; int status; /* avoid "core dumped" message */ pid = fork(); if (pid < 0) exit(2); if (pid > 0) { /* parent */ pid = waitpid(pid, &status, 0); if (pid < 0) exit(3); exit(!WIFEXITED(status)); } /* child */ i = *(unsigned int *)&a[[1]]; printf("%d\n", i); exit(0); } EOF ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \ conftest.c $LIBS >/dev/null 2>&1 if test ! -x conftest ; then dnl failed to compile for some reason ac_cv_lbl_unaligned_fail=yes else ./conftest >conftest.out if test ! -s conftest.out ; then ac_cv_lbl_unaligned_fail=yes else ac_cv_lbl_unaligned_fail=no fi fi rm -f -r conftest* core core.conftest ;; esac]) AC_MSG_RESULT($ac_cv_lbl_unaligned_fail) if test $ac_cv_lbl_unaligned_fail = yes ; then AC_DEFINE(LBL_ALIGN,1,[if unaligned access fails]) fi]) dnl dnl If the file .devel exists: dnl Add some warning flags if the compiler supports them dnl If an os prototype include exists, symlink os-proto.h to it dnl dnl usage: dnl dnl AC_LBL_DEVEL(copt) dnl dnl results: dnl dnl $1 (copt appended) dnl HAVE_OS_PROTO_H (defined) dnl os-proto.h (symlinked) dnl AC_DEFUN(AC_LBL_DEVEL, [rm -f os-proto.h if test "${LBL_CFLAGS+set}" = set; then $1="$$1 ${LBL_CFLAGS}" fi if test -f .devel ; then # # Skip all the warning option stuff on some compilers. # if test "$ac_lbl_cc_dont_try_gcc_dashW" != yes; then AC_LBL_CHECK_UNKNOWN_WARNING_OPTION_ERROR() AC_LBL_CHECK_COMPILER_OPT($1, -Wall) AC_LBL_CHECK_COMPILER_OPT($1, -Wsign-compare) AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-prototypes) AC_LBL_CHECK_COMPILER_OPT($1, -Wstrict-prototypes) AC_LBL_CHECK_COMPILER_OPT($1, -Wshadow) AC_LBL_CHECK_COMPILER_OPT($1, -Wdeclaration-after-statement) AC_LBL_CHECK_COMPILER_OPT($1, -Wused-but-marked-unused) fi AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT() # # We used to set -n32 for IRIX 6 when not using GCC (presumed # to mean that we're using MIPS C or MIPSpro C); it specified # the "new" faster 32-bit ABI, introduced in IRIX 6.2. I'm # not sure why that would be something to do *only* with a # .devel file; why should the ABI for which we produce code # depend on .devel? # os=`echo $host_os | sed -e 's/\([[0-9]][[0-9]]*\)[[^0-9]].*$/\1/'` name="lbl/os-$os.h" if test -f $name ; then ln -s $name os-proto.h AC_DEFINE(HAVE_OS_PROTO_H, 1, [if there's an os_proto.h for this platform, to use additional prototypes]) else AC_MSG_WARN(can't find $name) fi fi]) dnl dnl Improved version of AC_CHECK_LIB dnl dnl Thanks to John Hawkinson (jhawk@mit.edu) dnl dnl usage: dnl dnl AC_LBL_CHECK_LIB(LIBRARY, FUNCTION [, ACTION-IF-FOUND [, dnl ACTION-IF-NOT-FOUND [, OTHER-LIBRARIES]]]) dnl dnl results: dnl dnl LIBS dnl dnl XXX - "AC_LBL_LIBRARY_NET" was redone to use "AC_SEARCH_LIBS" dnl rather than "AC_LBL_CHECK_LIB", so this isn't used any more. dnl We keep it around for reference purposes in case it's ever dnl useful in the future. dnl define(AC_LBL_CHECK_LIB, [AC_MSG_CHECKING([for $2 in -l$1]) dnl Use a cache variable name containing the library, function dnl name, and extra libraries to link with, because the test really is dnl for library $1 defining function $2, when linked with potinal dnl library $5, not just for library $1. Separate tests with the same dnl $1 and different $2's or $5's may have different results. ac_lib_var=`echo $1['_']$2['_']$5 | sed 'y%./+- %__p__%'` AC_CACHE_VAL(ac_cv_lbl_lib_$ac_lib_var, [ac_save_LIBS="$LIBS" LIBS="-l$1 $5 $LIBS" AC_TRY_LINK(dnl ifelse([$2], [main], , dnl Avoid conflicting decl of main. [/* Override any gcc2 internal prototype to avoid an error. */ ]ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus extern "C" #endif ])dnl [/* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $2(); ]), [$2()], eval "ac_cv_lbl_lib_$ac_lib_var=yes", eval "ac_cv_lbl_lib_$ac_lib_var=no") LIBS="$ac_save_LIBS" ])dnl if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then AC_MSG_RESULT(yes) ifelse([$3], , [changequote(, )dnl ac_tr_lib=HAVE_LIB`echo $1 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` changequote([, ])dnl AC_DEFINE_UNQUOTED($ac_tr_lib) LIBS="-l$1 $LIBS" ], [$3]) else AC_MSG_RESULT(no) ifelse([$4], , , [$4 ])dnl fi ]) dnl dnl AC_LBL_LIBRARY_NET dnl dnl This test is for network applications that need socket() and dnl gethostbyname() -ish functions. Under Solaris, those applications dnl need to link with "-lsocket -lnsl". Under IRIX, they need to link dnl with "-lnsl" but should *not* link with "-lsocket" because dnl libsocket.a breaks a number of things (for instance: dnl gethostbyname() under IRIX 5.2, and snoop sockets under most dnl versions of IRIX). dnl dnl Unfortunately, many application developers are not aware of this, dnl and mistakenly write tests that cause -lsocket to be used under dnl IRIX. It is also easy to write tests that cause -lnsl to be used dnl under operating systems where neither are necessary (or useful), dnl such as SunOS 4.1.4, which uses -lnsl for TLI. dnl dnl This test exists so that every application developer does not test dnl this in a different, and subtly broken fashion. dnl It has been argued that this test should be broken up into two dnl seperate tests, one for the resolver libraries, and one for the dnl libraries necessary for using Sockets API. Unfortunately, the two dnl are carefully intertwined and allowing the autoconf user to use dnl them independantly potentially results in unfortunate ordering dnl dependancies -- as such, such component macros would have to dnl carefully use indirection and be aware if the other components were dnl executed. Since other autoconf macros do not go to this trouble, dnl and almost no applications use sockets without the resolver, this dnl complexity has not been implemented. dnl dnl The check for libresolv is in case you are attempting to link dnl statically and happen to have a libresolv.a lying around (and no dnl libnsl.a). dnl AC_DEFUN(AC_LBL_LIBRARY_NET, [ # Most operating systems have gethostbyname() in the default searched # libraries (i.e. libc): # Some OSes (eg. Solaris) place it in libnsl # Some strange OSes (SINIX) have it in libsocket: AC_SEARCH_LIBS(gethostbyname, nsl socket resolv) # Unfortunately libsocket sometimes depends on libnsl and # AC_SEARCH_LIBS isn't up to the task of handling dependencies like this. if test "$ac_cv_search_gethostbyname" = "no" then AC_CHECK_LIB(socket, gethostbyname, LIBS="-lsocket -lnsl $LIBS", , -lnsl) fi AC_SEARCH_LIBS(socket, socket, , AC_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", , -lnsl)) # DLPI needs putmsg under HPUX so test for -lstr while we're at it AC_SEARCH_LIBS(putmsg, str) ]) dnl dnl Test for __attribute__ dnl AC_DEFUN(AC_C___ATTRIBUTE__, [ AC_MSG_CHECKING(for __attribute__) AC_CACHE_VAL(ac_cv___attribute__, [ AC_COMPILE_IFELSE([ AC_LANG_SOURCE([[ #include static void foo(void) __attribute__ ((noreturn)); static void foo(void) { exit(1); } int main(int argc, char **argv) { foo(); } ]])], ac_cv___attribute__=yes, ac_cv___attribute__=no)]) if test "$ac_cv___attribute__" = "yes"; then AC_DEFINE(HAVE___ATTRIBUTE__, 1, [define if your compiler has __attribute__]) else # # We can't use __attribute__, so we can't use __attribute__((unused)), # so we define _U_ to an empty string. # V_DEFS="$V_DEFS -D_U_=\"\"" fi AC_MSG_RESULT($ac_cv___attribute__) ]) dnl dnl Test whether __attribute__((unused)) can be used without warnings dnl AC_DEFUN(AC_C___ATTRIBUTE___UNUSED, [ AC_MSG_CHECKING([whether __attribute__((unused)) can be used without warnings]) AC_CACHE_VAL(ac_cv___attribute___unused, [ save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" AC_COMPILE_IFELSE([ AC_LANG_SOURCE([[ #include #include int main(int argc __attribute((unused)), char **argv __attribute((unused))) { printf("Hello, world!\n"); return 0; } ]])], ac_cv___attribute___unused=yes, ac_cv___attribute___unused=no)]) CFLAGS="$save_CFLAGS" if test "$ac_cv___attribute___unused" = "yes"; then V_DEFS="$V_DEFS -D_U_=\"__attribute__((unused))\"" else V_DEFS="$V_DEFS -D_U_=\"\"" fi AC_MSG_RESULT($ac_cv___attribute___unused) ]) dnl dnl Test whether __attribute__((format)) can be used without warnings dnl AC_DEFUN(AC_C___ATTRIBUTE___FORMAT, [ AC_MSG_CHECKING([whether __attribute__((format)) can be used without warnings]) AC_CACHE_VAL(ac_cv___attribute___format, [ save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" AC_COMPILE_IFELSE([ AC_LANG_SOURCE([[ #include extern int foo(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); int main(int argc, char **argv) { foo("%s", "test"); } ]])], ac_cv___attribute___format=yes, ac_cv___attribute___format=no)]) CFLAGS="$save_CFLAGS" if test "$ac_cv___attribute___format" = "yes"; then AC_DEFINE(__ATTRIBUTE___FORMAT_OK, 1, [define if your compiler allows __attribute__((format)) without a warning]) fi AC_MSG_RESULT($ac_cv___attribute___format) ]) dnl dnl Checks to see if tpacket_stats is defined in linux/if_packet.h dnl If so then pcap-linux.c can use this to report proper statistics. dnl dnl -Scott Barron dnl AC_DEFUN(AC_LBL_TPACKET_STATS, [AC_MSG_CHECKING(if if_packet.h has tpacket_stats defined) AC_CACHE_VAL(ac_cv_lbl_tpacket_stats, AC_TRY_COMPILE([ # include ], [struct tpacket_stats stats], ac_cv_lbl_tpacket_stats=yes, ac_cv_lbl_tpacket_stats=no)) AC_MSG_RESULT($ac_cv_lbl_tpacket_stats) if test $ac_cv_lbl_tpacket_stats = yes; then AC_DEFINE(HAVE_TPACKET_STATS,1,[if if_packet.h has tpacket_stats defined]) fi]) dnl dnl Checks to see if the tpacket_auxdata struct has a tp_vlan_tci member. dnl dnl usage: dnl dnl AC_LBL_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI dnl dnl results: dnl dnl HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI (defined) dnl dnl NOTE: any compile failure means we conclude that it doesn't have dnl that member, so if we don't have tpacket_auxdata, we conclude it dnl doesn't have that member (which is OK, as either we won't be using dnl code that would use that member, or we wouldn't compile in any case). dnl AC_DEFUN(AC_LBL_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI, [AC_MSG_CHECKING(if tpacket_auxdata struct has tp_vlan_tci member) AC_CACHE_VAL(ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci, AC_TRY_COMPILE([ # include # include ], [u_int i = sizeof(((struct tpacket_auxdata *)0)->tp_vlan_tci)], ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci=yes, ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci=no)) AC_MSG_RESULT($ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci) if test $ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci = yes ; then HAVE_LINUX_TPACKET_AUXDATA=tp_vlan_tci AC_SUBST(HAVE_LINUX_TPACKET_AUXDATA) AC_DEFINE(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI,1,[if tp_vlan_tci exists]) fi]) dnl dnl Checks to see if Solaris has the dl_passive_req_t struct defined dnl in . dnl dnl usage: dnl dnl AC_LBL_DL_PASSIVE_REQ_T dnl dnl results: dnl dnl HAVE_DLPI_PASSIVE (defined) dnl AC_DEFUN(AC_LBL_DL_PASSIVE_REQ_T, [AC_MSG_CHECKING(if dl_passive_req_t struct exists) AC_CACHE_VAL(ac_cv_lbl_has_dl_passive_req_t, AC_TRY_COMPILE([ # include # include ], [u_int i = sizeof(dl_passive_req_t)], ac_cv_lbl_has_dl_passive_req_t=yes, ac_cv_lbl_has_dl_passive_req_t=no)) AC_MSG_RESULT($ac_cv_lbl_has_dl_passive_req_t) if test $ac_cv_lbl_has_dl_passive_req_t = yes ; then AC_DEFINE(HAVE_DLPI_PASSIVE,1,[if passive_req_t primitive exists]) fi]) libpcap-1.8.1/SUNOS4/0000755000026300017510000000000013003775545012262 5ustar mcrmcrlibpcap-1.8.1/SUNOS4/nit_if.o.sun30000644000026300017510000001025313003771737014601 0ustar mcrmcr €¸¬H@NVÿìH×<€ ®f.~(|` ¾­m R‡(M*TJfð ‡fFüšxpÿ`ìJ®gpÿ`à~.(|`¾­m¾­n üšxpÿ`º(M*TJfàHxHx N¹PO&@J‹f ü šxpÿ`r Ó«*k +K*”(+n n!M n!M8B­B­+GB­B­ HxHxN¹PO&@J€g: k| $k 4¼05|»€ 5|.à rÓ«HS n/( h P PNPO Lî<€ÿìN^NuNVÿìH×<*nHxHm$N¹PO(m$l ,gJŠg B§HRN¹PO-|ÿü`·Ìg-Kÿü nÿü&PJ‹fîJ‹fHy N¹XO nÿü ”B­/,N¹XOpLî<ÿìN^NuNVÿì n hp( J€g r°grr°gX €†fö n h gHx/.N¹PO n h ý n h g¼/. /.N¹PO`´/. /.N¹öPO`  n -h ÿü-hÿø .ÿüT€-@ÿìJ®ÿøgr nÿø hJ( fd nÿüJPf\/.ÿøN¹ XO-@ÿôf /. N¹`H nÿì1h n h-h ÿð/.ÿü/.ÿô/.ÿð nÿð h.NOï /. N¹` /. N¹XOpN^NuNVÿÜH×<À n*h n (h .  €€pg €À i f–J­ fŽ n h|‚ ~9)G/. /.N¹PO`Â&m n h$h HR/HS k2NOï )@J¬fv n h| ~ )G `l n h$h HxHRN¹PO&@J‹f n h|‚ ~)G`4+K n h| B¬ ` n h h -Pÿü| .ÿÿg@Jlg|` -fHx/- N¹PO,J†g2 n h|‚ )F` -gB§/- N¹PO,fÎ~ðÏ­.ÿÿ~À‡­ n h| B¬ `~ n h h -~À‡ € n h| ~)G `P n h h +PJ­g ­d~+G n h| B¬ HxHxN¹PO-@ÿügJ­g -` <Ü-@ÿø ®dÿønp` ®ÿønp`p-@ÿô nÿü h| nÿü&h 6¼0 .ÿøë€L.ÿô7@ .ÿøç€L.ÿô7@ nÿü~ߨ/.ÿü/.N¹PO`p n h h ­ n h| ~)G `J  €€pgþ( €€pgþè €€ pgý €Àpgþ¦ €Àpg¨ €À i gýb n h|‚ /. /.N¹POpLî<ÀÿÜN^NuNVÿàH×<ÀB®ÿü&y`4 + °®f( nJ¨ g +~À‡g/+N¹XOJ€f R«&SJ‹fÈJ‹gÐ.+//. /.N¹HOï *@Jf¨R«`¨Jg $S`4 * °®f( nJ¨ g *g/*N¹XOJ€f Rª$RJŠfÈJŠgB¾ªfHUN¹XO(@JŒf,Rª`&/*/. /.N¹HOï (@JŒfRª`.* +|À†gî| +gP† +gX† +gX†Hx/N¹PO-@ÿüfHUN¹XOR«`¼ nÿü h| +g$ nÿü-hÿøAù"nÿø#h" nÿüP¨ +g nÿü-hÿø nÿø « nÿüX¨ +g$ nÿü-hÿø n (Ш nÿø € nÿüX¨HU/.ÿüN¹PO*nÿüHU k/( k h P PNPO&J*LJ‹fþ^pLî<ÀÿàN^NuNVÿìH×0à*n..,-J‡g z…¼€cž…,*Ú­V…äåHx/N¹PO(@J€fp`R lB( l (…)@)@ /-/,/N¹Oï -ѬJ†o/,/B§/. N¹Ý¬ Lî0àÿìN^NuNV/.N¹XOpN^NuNVÿðH×8B®ÿüIîÿü&n`NB§ +« //+ / HzÿÀN¹Oï*@Jf J®ÿüg /.ÿüN¹XOHSN¹XOp`((M&kJ‹f® .ÿüLî8ÿðN^Nu@(#)nit_if.c 1.24 88/02/09 Copyr 1987 Sun Micro 0껀.à4 ° ° ¾ Úsnit_close nonexistent instancesnitPTP„$Pâ$PJ,Pl8PtP”@š.P°7P,P4PH@Ž@ 7PÞ7Pê#PJP¬P 8PT8Pö$PŠP P,PVP€@ÆPè"P@Z$Pj#Pœ-P5P‚$P¸PÚ6Pø7P 2P L%P V#P2@F@J@R@Z@n@v@z@  €&* Ú6=F O^kHw@‹— ª³4¿Ó öÞ °êòú î#.€7>F@RYajr{ö‹ ¾— ª°¸¾ÅÂÏÖßéñü _cp_mblks_to_mbufs_sccsid_lbolt_qs_snit_winit_nproc_whichqs_avenrun_domainnamelen_hostnamelen_snit_cpmsg_rawintrq_hostname_tz_canput_nisoftc_boottime_mclgetx_snit_close_etherbroadcastaddr_snit_info_snit_minfo_m_want_ifunit_tick_procNPROC_phz_free_mbuffed_mblk_snit_open_pidhash_bcopy_qreply_domainname_mfree_dupmsg_freemsg_allocb_m_freem_hz_snit_ioctl_snit_rinit_mclfree_freeproc_proc_flushq_time_panic_snit_put_ifnet_allproc_zombproc_mbstat_snit_intr_linkb_m_cpytoc_freeb_ifpromisclibpcap-1.8.1/SUNOS4/nit_if.o.sun4c.4.0.3c0000644000026300017510000001225313003771737015553 0ustar mcrmcr ðÄL`ã¿ ³.`€¦à€³>`²`ú@¶ €"€ €¦áÔ`€¦À &€ €¦á²ú@¶à€2¿ÿùÔ`€¦á2€"’ – ¶?ÿ€SÖ(4Ѐ"€€N¶?ÿ¶`ÿ²àú@€"€’ à`€¦À&€’ â`€¦À4€²¤ ¶?ÿ€<ä(4Ðú@€2¿ÿóà`’ @ ¸€2€è ¦ ¶?ÿ€-æ(4Ð’ ¨ è' ú  ø'`ì@ì'@ú&@ð'`ú& ú& 8À'`À'`ö'`À'`@À'` ²€€î`´ ô-à ú` . 0Ð7@’c€Ò7`  ”¢àÔ7` Ö`’–àÖ&` Â@Â@ŸÀ@Ð Çà‘èã¿  $@’ ö úà Ðà€Š "€ €"€’ @¸`ú€"€ €€§@"€€¸ú€2¿ÿû€§@€2€ÔÀ@ ÔÀÔ'À& @ÐàÇà‘è ã¿ Ò`Ò ` € €H€¢`€!€¢`€€¢`†€BÐ` Ð €Š "€ Ú` ’ @ú` Ö@– àý– àÿÖ/@Ú` Ú @€‹`€0’@€.’@-€)ú` Ð`¶`€€!ä ä   €€ê@€€@¸€2€îà @€”î6à Ð ’Ð Â 0ŸÀ@@€@Çà‘è ã¿ ú ö`  øÀ’`€§ €0’a €§ 2€½ Ð` €2€¹ Ò`” ‚Ô*` – 9Ö&à’@€ÎÔ`Ô  Â`4ŸÀ@’Ð&àÞà€"€ä`à`¢ ‚€»â, ¦ æ,  ¨ €¶è&à Ð`’ @Ð ¸€2€ø'` î` ‚Ð-à ’ €¨Ò&àÔ`– Ö*  €£À&à ô`¸ ô  ô€€Ž "€è`àà€"€â`€ ¸ €Œ`2€€Ð` @’ ¸€"€î`ä`¦ ‚æ,  €‡ø&à€ "€ î`Ð` @’ €"€î`ê`¬ ‚ì-` €yÐ&à´ ® ÿðî'`Ô`𠔀Ô'`Ø`Ú+ €nÀ&à Þ`¨ Þà ú`ª º`ú#Àæ`è,à €cê&à ì`ì  ì€ì'`Ò`€ "€ Ø`Ô`€¢ :€Ø`– Ö'`Ø`š Ú+ À&à ’ @ ¶€"€K’Þ`€"€º%Üú`€§`d4€€§a€¸ 4€¸ ¸ âठä,` ôà ¦ 0æ6€’@‘/`Ð6  ‘/`@’Ð6  èਠè&à@’€(’ì`” ì  ú`– ú%€Ò`Ô*` €Ö&à ’`€§ ¿ÿx ’`€§ ¿ÿ´ ’`€§ ¿ÿ]0’`€§ ¿ÿ¡0’`€§ ¿ÿä0’a €§ "¿ÿ=ú` Ø`š ‚Ú+ ’@² Çà‘èã¿ ø €"€€Ò €¢@2€øÔ  € €Ö €Šà"€ ø@Ð €2€ €Ø ˜ Ø' ø€2¿ÿëÒ €€¬è ’”@©¬€2€€Þ žà€ŸÞ' ?ÿÜ#ÿÿ¦€™¤€"€—º ú€"€€Ò` €¢@2€ú@Ô  € €Ö`€Šà"€ ú@@Ð`€2€ €Ø`˜ Ø'`ú@€2¿ÿëÒ` €"€Ô Þ`€£À2€ Ô`@ª€2€Ô à`  € à'`’@iª€2€è`Ð` Ð'`Ô €Š "€PÂ Ö ¶ €Šà"€Ø ¶ Ø €‹ "€Ú ¶àÚ €‹`"€’ ¶à’ @¶€2€âà@Þ žà€:Þ'  Ð,` Ò €Š`"€Ø îà–àØÀÖàØ%àÖ%àÞÀÐàž ÀŸ3à Ð%àÔà” Ô&àØ €‹ "€ â îàÚ Ú%ÀÞàžàÞ&àâ €Œ`"€ ’îàРҠ Ð%ÀÖà–àÖ&à’@¬Â ’Â` Â@Â@Ð ŸÀ@Ð ¸€¿ÿk¬º Çà‘èã¿ ú €"€ø ´& €§@(€ø ºø ’ ¸@¸ ¹7 ¹/ @´€2€ê €´ À-` ì ì ¬%€ì& ì&  ÐÒ @Ô ð Ô €”€€ Ô& Ö ”’ @Ø ˜Ø& Çà‘èã¿ @Çà‘è 㿘€¸¿ü€À'¿üÖ Ò Ô –"À  ’@˜ º€2€ ú'Ô¿ü€ €@пü@€° 𠸀2¿ÿçÖ ð¿üÇàè@(#) $Header: nit_if.c,v 1.4 90/03/20 18:18:19 leres Exp $ sun4c (LBL)@(#)nit_if.c 1.24++ 88/02/09 Copyr 1987 Sun Micro껀.àsnitsnit_close nonexistent instance ˆ ‹| ˆŒ ‹ä†ÿÿÿL†ÿÿþ´È&†ÿÿþ8ä ˆð ˆø†ÿÿþ ˆ ‹D ÍH%†ÿÿý¸L Í\†ÿÿý¤´&†ÿÿýLä7†ÿÿý\†ÿÿü¤Œ†ÿÿütœ6†ÿÿüd7†ÿÿûøp+†ÿÿûø†ÿÿû4†ÿÿú̆ÿÿúh:†ÿÿù˜x:†ÿÿùˆ”7†ÿÿùl<7†ÿÿøÄT ˆX ‹˜ †ÿÿøhh †ÿÿ÷˜´#†ÿÿ÷L X†ÿÿö¨ p6†ÿÿö ¤ˆ ¨‹ <†ÿÿõÄ Ä†ÿÿõ< †ÿÿôü 0†ÿÿôÐ P†ÿÿô° „ L ˆ L †ÿÿôp ¸ †ÿÿôH À6†ÿÿô@€ È”˜À  l¨l¼ lÄ |È ˜ À" „.¬: lF ˜R |^hqzƒŒ€•Ÿ@©°¶¿ÆÐ×Ýãíõül #.6=AI `\ck ðr L…@‘›£®· ÀË ´ÖPáåíõù  8&+_phz_hostnamelen_snit_close_snit_cpmsg_snit_ioctl_snit_minfo_snit_winit_snit_rinit_boottime_mclfree_m_freem_mclgetx_nisoftc_pidhash_freeproc_hostname_bcopy_proc_whichqs_freeb_m_cpytoc_ifnet_time_tick_rawintrq_allocb_linkb_lbolt_snit_put_domainnamelen_mfree_ifpromisc_canput_nproc_hz_dupmsg_cp_mblks_to_mbufs_panic_flushq_rcsid_free_mbuffed_mblk_domainname_zombproc_ifunit_procNPROC_allproc_avenrun_snit_open_snit_info_snit_intr_qs_m_want_mbstat_tz_freemsg_qreply_etherbroadcastaddr_sccsid.mullibpcap-1.8.1/SUNOS4/nit_if.o.sparc0000644000026300017510000001213413003771737015021 0ustar mcrmcr ð¸¸X`ã¿ ³.`€¦à€³>`²`ú@¶ €"€ €¦áÔ`€¦À &€ €¦á²ú@¶à€2¿ÿùÔ`€¦á2€0’ – ¶?ÿ€^Ö(4Ѐ"€€Y¶?ÿ¶`ÿ²àú@€"€!’ à`€¦À6€ â`’ @ ¸€2€è ¦ ¶?ÿ€Dæ(4Ѐ¦À4€²¤ ¶?ÿ€=ä(4Ðú@€"€’ à`€¦À6¿ÿóâ`’ @ ¸€"¿ÿé¦ è ’ ¨ è' ú  ø'`ì@ì'@ú&@ð'`ú& ú& 8À'`À'`ö'`À'`@À'` ²€€î`´ ô-à ú` . 0Ð7@’c€Ò7`  ”¢àÔ7` Ö`’–àÖ&` Â@Â@ŸÀ@Ð Çà‘èã¿  $@’ ö úà Ðà€Š "€ €"€’ @¸`ú€"€ €€§@"€€¸ú€2¿ÿû€§@€2€ÔÀ@ ÔÀÔ'À& @ÐàÇà‘è ã¿ Ò`Ò ` € €H€¢`€!€¢`€€¢`†€BÐ` Ð €Š "€ Ú` ’ @ú` Ö@– àý– àÿÖ/@Ú` Ú @€‹`€0’@€.’@-€)ú` Ð`¶`€€!ä ä   €€ê@€€@û¸€2€îà @€”î6à Ð ’Ð Â 0ŸÀ@@€@Çà‘è ã¿ ú ö`  øÀ’`€§ €0’a €§ 2€ Ð` €2€  Ò`” ‚Ô*` – 9Ö&à’@€!’`€§ €F ’`€§ €‚ ’`€§ €+0’`€§ €o0’`€§ €²0’a €§ "€ ú` Ø`š ‚Ú+ ’@² Çà‘èÔ`Ô  Â`4ŸÀ@’Ð&àÞà€"€ä`à`¢ ‚¿ÿíâ, ¦ æ,  ¨ ¿ÿèè&à Ð`’ @Ð ¸€2€ø'` î` ‚Ð-à ’ ¿ÿÚÒ&àÔ`– Ö*  ¿ÿÕÀ&à ô`¸ ô  ô€€Ž "€è`àà€"€â`€ ¸ €Œ`2€€Ð` @’ ¸€"€î`ä`¦ ‚æ,  ¿ÿ¹ø&à€ "€ î`Ð` @’ €"€î`ê`¬ ‚ì-` ¿ÿ«Ð&à´ ® ÿðî'`Ô`𠔀Ô'`Ø`Ú+ ¿ÿ À&à Þ`¨ Þà ú`ª º`ú#Àæ`è,à ¿ÿ•ê&à ì`ì  ì€ì'`Ò`€ "€ Ø`Ô`€¢ :€Ø`– Ö'`Ø`š Ú+ À&à ’ @ ¶€"¿ÿ}’Þ`€"€º%Üú`€§`d4€€§a€¸ 4€¸ ¸ âठä,` ôà ¦ 0æ6€’@‘/`Ð6  ‘/`@’Ð6  èਠè&à@’¿ÿZ’ì`” ì  ú`– ú%€Ò`Ô*` ¿ÿOÖ&à ã¿ ø €"€€Ò €¢@2€øÔ  € €Ö €Šà"€ ø@Ð €2€ €Ø ˜ Ø' ø€2¿ÿëÒ €€ è ’”@®€"€ Þ €"€”º €"€‘º €úžà€ŒÞ' €¤@2€ú@ä  €€æ`€Œà"€ ú@@Ð`€2€ €Ð` Ð'`ú@€2¿ÿëâ` €"€à Ô`€¢€2€ Ô`@ª€2€à Ö`–à€ Ö'`’@cª€2€è`Ú`š`Ú'`à €Œ "€J ⠶ €Œ`"€ä ¶ ä €Œ "€æ ¶àæ €Œà"€’ ¶à’ @¶€2€Ôà@Ð  €4Ð' – Ö*  Ø €‹ "€ Ð ìàžààÀÞàà% Þ% äठä&àÐ €Š "€ Ø ìàÒ Ò%€Ôà” Ô&àØ €‹ "€ ’ìàÚ Þ š@Ú%€âà¢`â&à’@®Â ’Â` Â@Â@Ð ŸÀ@Ð ¸€¿ÿq®º Çà‘èã¿ ú €"€ø ´& €§@(€ø ºø ’ ¸@¸ ¹7 ¹/ @´€2€ê €´ À-` ì ì ¬%€ì& ì&  ÐÒ @Ô ð Ô €”€€ Ô& Ö ”’ @Ø ˜Ø& Çà‘èã¿ @Çà‘è 㿘€¸¿ü€À'¿üÖ Ò Ô –"À  ’@˜ º€2€ ú'Ô¿ü€ €@пü@€° 𠸀2¿ÿçÖ ð¿üÇàè@(#)nit_if.c 1.24 88/02/09 Copyr 1987 Sun Micro껀.àsnitsnit_close nonexistent instance ˆ ‹| ˆŒ ‹´†ÿÿÿL†ÿÿþäx†ÿÿþˆô&†ÿÿþ  ˆ ˆ$†ÿÿýÜ, ˆ0 ‹p …t%†ÿÿýŒx …ˆ†ÿÿýxà&†ÿÿý 6†ÿÿüðˆ†ÿÿüx¸†ÿÿüHÈ5†ÿÿü846†ÿÿûÌ´6†ÿÿûL *†ÿÿúਆÿÿúXä†ÿÿú°†ÿÿùP9†ÿÿøè(9†ÿÿøØD6†ÿÿø¼€ ˆ„ ‹Ä †ÿÿø<| †ÿÿ÷„È#†ÿÿ÷8 l†ÿÿö” „5†ÿÿö| ¸ˆ ¼‹ 8†ÿÿõÈ À†ÿÿõ@ †ÿÿõ ,†ÿÿôÔ L†ÿÿô´ € H „ H Œ †ÿÿôt ´ †ÿÿôL ¼5†ÿÿôD4 €HLìT \˜p x 0| L ì" €.Ø: F LR 0^hqzƒŒ€•Ÿ@©°¶¿ÆÐ×Ýãíõü˜ #.6=AI \\ck H~@Š”œ§° ¹Ä hÏ|ÚÞæîòû ð$_phz_hostnamelen_snit_close_snit_cpmsg_snit_ioctl_snit_minfo_snit_winit_snit_rinit_boottime_mclfree_m_freem_mclgetx_nisoftc_pidhash_freeproc_hostname_bcopy_proc_whichqs_freeb_m_cpytoc_ifnet_time_tick_rawintrq_allocb_linkb_lbolt_snit_put_domainnamelen_mfree_ifpromisc_canput_nproc_hz_dupmsg_cp_mblks_to_mbufs_panic_flushq_free_mbuffed_mblk_domainname_zombproc_ifunit_procNPROC_allproc_avenrun_snit_open_snit_info_snit_intr_qs_m_want_mbstat_tz_freemsg_qreply_etherbroadcastaddr_sccsid.mullibpcap-1.8.1/README.sita0000644000026300017510000000464113003771737013112 0ustar mcrmcrThe following instructions apply if you have a Linux platform and want libpcap to support the 'ACN' WAN/LAN router product from from SITA (http://www.sita.aero) This might also work on non-Linux Unix-compatible platforms, but that has not been tested. See also the libpcap INSTALL.txt file for further libpcap configuration options. These additions/extensions have been made to PCAP to allow it to capture packets from a SITA ACN device (and potentially others). To enable its support you need to ensure that the distribution has a correct configure.ac file; that can be created if neccessay by using the normal autoconf procedure of: aclocal autoconf autoheader automake Then run configure with the 'sita' option: ./configure --with-sita Applications built with libpcap configured in this way will only detect SITA ACN interfaces and will not capture from the native OS packet stream. The SITA extension provides a remote datascope operation for capturing both WAN and LAN protocols. It effectively splits the operation of PCAP into two halves. The top layer performs the majority of the work, but interfaces via a TCP session to remote agents that provide the lower layer functionality of actual sniffing and filtering. More detailed information regarding the functions and inter-device protocol and naming conventions are described in detail in 'pcap-sita.html'. pcap_findalldevs() reads the local system's /etc/hosts file looking for host names that match the format of IOP type devices. ie. aaa_I_x_y and then queries each associated IP address for a list of its WAN and LAN devices. The local system the aggregates the lists obtained from each IOP, sorts it, and provides it (to Wireshark et.al) as the list of monitorable interfaces. Once a valid interface has been selected, pcap_open() is called which opens a TCP session (to a well known port) on the target IOP and tells it to start monitoring. All captured packets are then forwarded across that TCP session back to the local 'top layer' for forwarding to the actual sniffing program (wireshark...) Note that the DLT_SITA link-layer type includes a proprietary header that is documented as part of the SITA dissector of Wireshark and is also described in 'pcap-sita.html' for posterity sake. That header provides: - Packet direction (in/out) (1 octet) - Link layer hardware signal status (1 octet) - Transmit/Receive error status (2 octets) - Encapsulated WAN protocol ID (1 octet) libpcap-1.8.1/pcap-bt-linux.h0000644000026300017510000000341313003771737014123 0ustar mcrmcr/* * Copyright (c) 2006 Paolo Abeni (Italy) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Bluetooth sniffing API implementation for Linux platform * By Paolo Abeni */ /* * Prototypes for Bluetooth-related functions */ int bt_findalldevs(pcap_if_t **alldevsp, char *err_str); pcap_t *bt_create(const char *device, char *ebuf, int *is_ours); libpcap-1.8.1/configure.ac0000644000026300017510000014125413003771737013563 0ustar mcrmcrdnl dnl Copyright (c) 1994, 1995, 1996, 1997 dnl The Regents of the University of California. All rights reserved. dnl dnl Process this file with autoconf to produce a configure script. dnl # # See # # http://ftp.gnu.org/gnu/config/README # # for the URLs to use to fetch new versions of config.guess and # config.sub. # AC_PREREQ(2.61) AC_INIT(pcap.c) AC_CANONICAL_SYSTEM AC_LBL_C_INIT_BEFORE_CC(V_CCOPT, V_INCLS) AC_PROG_CC AC_LBL_C_INIT(V_CCOPT, V_INCLS) AC_LBL_SHLIBS_INIT AC_LBL_C_INLINE AC_C___ATTRIBUTE__ if test "$ac_cv___attribute__" = "yes"; then AC_C___ATTRIBUTE___UNUSED AC_C___ATTRIBUTE___FORMAT fi AC_CHECK_HEADERS(sys/bitypes.h) AC_CHECK_TYPE([int8_t], , [AC_DEFINE([int8_t], [signed char], [Define to `signed char' if int8_t not defined.])], [AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_BITYPES_H #include #endif]) AC_CHECK_TYPE([u_int8_t], , [AC_DEFINE([u_int8_t], [unsigned char], [Define to `unsigned char' if u_int8_t not defined.])], [AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_BITYPES_H #include #endif]) AC_CHECK_TYPE([int16_t], , [AC_DEFINE([int16_t], [short], [Define to `short' if int16_t not defined.])] [AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_BITYPES_H #include #endif]) AC_CHECK_TYPE([u_int16_t], , [AC_DEFINE([u_int16_t], [unsigned short], [Define to `unsigned short' if u_int16_t not defined.])], [AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_BITYPES_H #include #endif]) AC_CHECK_TYPE([int32_t], , [AC_DEFINE([int32_t], [int], [Define to `int' if int32_t not defined.])], [AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_BITYPES_H #include #endif]) AC_CHECK_TYPE([u_int32_t], , [AC_DEFINE([u_int32_t], [unsigned int], [Define to `unsigned int' if u_int32_t not defined.])], [AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_BITYPES_H #include #endif]) AC_CHECK_TYPE([int64_t], , [AC_DEFINE([int64_t], [long long], [Define to `long long' if int64_t not defined.])], [AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_BITYPES_H #include #endif]) AC_CHECK_TYPE([u_int64_t], , [AC_DEFINE([u_int64_t], [unsigned long long], [Define to `unsigned long long' if u_int64_t not defined.])], [AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_BITYPES_H #include #endif]) # # Try to arrange for large file support. # AC_SYS_LARGEFILE AC_FUNC_FSEEKO dnl dnl Even if were, on all OSes that support BPF, fixed to dnl include , and we were to drop support for older dnl releases without that fix, so that pcap-bpf.c doesn't need to dnl include , the test program in "AC_LBL_FIXINCLUDES" dnl in "aclocal.m4" uses it, so we would still have to test for it dnl and set "HAVE_SYS_IOCCOM_H" if we have it, otherwise dnl "AC_LBL_FIXINCLUDES" wouldn't work on some platforms such as Solaris. dnl AC_CHECK_HEADERS(sys/ioccom.h sys/select.h sys/sockio.h limits.h) AC_CHECK_HEADERS(linux/types.h) AC_CHECK_HEADERS(linux/if_packet.h netpacket/packet.h netpacket/if_packet.h) AC_CHECK_HEADERS(net/pfvar.h, , , [#include #include #include ]) if test "$ac_cv_header_net_pfvar_h" = yes; then # # Check for various PF actions. # AC_MSG_CHECKING(whether net/pfvar.h defines PF_NAT through PF_NORDR) AC_TRY_COMPILE( [#include #include #include #include ], [return PF_NAT+PF_NONAT+PF_BINAT+PF_NOBINAT+PF_RDR+PF_NORDR;], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_PF_NAT_THROUGH_PF_NORDR, 1, [define if net/pfvar.h defines PF_NAT through PF_NORDR]) ], AC_MSG_RESULT(no)) fi AC_CHECK_HEADERS(netinet/if_ether.h, , , [#include #include ]) if test "$ac_cv_header_netinet_if_ether_h" != yes; then # # The simple test didn't work. # Do we need to include first? # Unset ac_cv_header_netinet_if_ether_h so we don't # treat the previous failure as a cached value and # suppress the next test. # AC_MSG_NOTICE([Rechecking with some additional includes]) unset ac_cv_header_netinet_if_ether_h AC_CHECK_HEADERS(netinet/if_ether.h, , , [#include #include #include struct mbuf; struct rtentry; #include ]) fi case "$host_os" in linux*|uclinux*) AC_CHECK_HEADERS(linux/sockios.h linux/if_bonding.h,,, [ #include #include ]) ;; esac AC_LBL_FIXINCLUDES AC_CHECK_FUNCS(strerror strlcpy) needsnprintf=no AC_CHECK_FUNCS(vsnprintf snprintf,, [needsnprintf=yes]) if test $needsnprintf = yes; then AC_LIBOBJ([snprintf]) fi needstrtok_r=no AC_CHECK_FUNCS(strtok_r,, [needstrtok_r=yes]) if test $needstrtok_r = yes; then AC_LIBOBJ([strtok_r]) fi # # Do this before checking for ether_hostton(), as it's a # "gethostbyname() -ish function". # AC_LBL_LIBRARY_NET # # You are in a twisty little maze of UN*Xes, all different. # Some might not have ether_hostton(). # Some might have it, but not declare it in any header file. # Some might have it, but declare it in . # Some might have it, but declare it in # (And some might have it but document it as something declared in # , although appears to work.) # # Before you is a C compiler. # AC_CHECK_FUNCS(ether_hostton) if test "$ac_cv_func_ether_hostton" = yes; then # # OK, we have ether_hostton(). Do we have ? # if test "$ac_cv_header_netinet_if_ether_h" = yes; then # # Yes. Does it declare ether_hostton()? # AC_CHECK_DECL(ether_hostton, [ AC_DEFINE(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON,, [Define to 1 if netinet/if_ether.h declares `ether_hostton']) ],, [ #include #include #include #include struct mbuf; struct rtentry; #include #include ]) fi # # Did that succeed? # if test "$ac_cv_have_decl_ether_hostton" != yes; then # # No, how about , as on Linux? # AC_CHECK_HEADERS(netinet/ether.h) if test "$ac_cv_header_netinet_ether_h" = yes; then # # We have it - does it declare ether_hostton()? # Unset ac_cv_have_decl_ether_hostton so we don't # treat the previous failure as a cached value and # suppress the next test. # unset ac_cv_have_decl_ether_hostton AC_CHECK_DECL(ether_hostton, [ AC_DEFINE(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON,, [Define to 1 if netinet/ether.h declares `ether_hostton']) ],, [ #include ]) fi fi # # Is ether_hostton() declared? # if test "$ac_cv_have_decl_ether_hostton" != yes; then # # No, we'll have to declare it ourselves. # Do we have "struct ether_addr"? # AC_CHECK_TYPES(struct ether_addr,,, [ #include #include #include #include struct mbuf; struct rtentry; #include #include ]) AC_DEFINE(HAVE_DECL_ETHER_HOSTTON, 0, [Define to 1 if you have the declaration of `ether_hostton', and to 0 if you don't.]) else AC_DEFINE(HAVE_DECL_ETHER_HOSTTON, 1, [Define to 1 if you have the declaration of `ether_hostton', and to 0 if you don't.]) fi fi dnl to pacify those who hate protochain insn AC_MSG_CHECKING(if --disable-protochain option is specified) AC_ARG_ENABLE(protochain, AC_HELP_STRING([--disable-protochain],[disable \"protochain\" insn])) case "x$enable_protochain" in xyes) enable_protochain=enabled ;; xno) enable_protochain=disabled ;; x) enable_protochain=enabled ;; esac if test "$enable_protochain" = "disabled"; then AC_DEFINE(NO_PROTOCHAIN,1,[do not use protochain]) fi AC_MSG_RESULT(${enable_protochain}) # # valgrindtest directly uses the native capture mechanism, but # only tests with BPF and PF_PACKET sockets; only enable it if # we have BPF or PF_PACKET sockets. # VALGRINDTEST= # # SITA support is mutually exclusive with native capture support; # "--with-sita" selects SITA support. # AC_ARG_WITH(sita, AC_HELP_STRING([--with-sita],[include SITA support]), [ if test ! "x$withval" = "xno" ; then AC_DEFINE(SITA,1,[include ACN support]) AC_MSG_NOTICE(Enabling SITA ACN support) V_PCAP=sita fi ], [ dnl dnl Not all versions of test support -c (character special) but it's a dnl better way of testing since the device might be protected. So we dnl check in our normal order using -r and then check the for the /dev dnl guys again using -c. dnl dnl XXX This could be done for cross-compiling, but for now it's not. dnl if test -z "$with_pcap" && test "$cross_compiling" = yes; then AC_MSG_ERROR(pcap type not determined when cross-compiling; use --with-pcap=...) fi AC_ARG_WITH(pcap, AC_HELP_STRING([--with-pcap=TYPE],[use packet capture TYPE])) AC_MSG_CHECKING(packet capture type) if test ! -z "$with_pcap" ; then V_PCAP="$withval" elif test -r /dev/bpf -o -h /dev/bpf ; then # # Cloning BPF device. # V_PCAP=bpf AC_DEFINE(HAVE_CLONING_BPF,1,[define if you have a cloning BPF device]) # # We have BPF, so build valgrindtest with "make test". # VALGRINDTEST=valgrindtest elif test -r /dev/bpf0 ; then V_PCAP=bpf # # We have BPF, so build valgrindtest with "make test". # VALGRINDTEST=valgrindtest elif test -r /usr/include/net/pfilt.h ; then V_PCAP=pf elif test -r /dev/enet ; then V_PCAP=enet elif test -r /dev/nit ; then V_PCAP=snit elif test -r /usr/include/sys/net/nit.h ; then V_PCAP=nit elif test -r /usr/include/linux/socket.h ; then V_PCAP=linux # # XXX - this won't work with older kernels that have SOCK_PACKET # sockets but not PF_PACKET sockets. # VALGRINDTEST=valgrindtest elif test -r /usr/include/net/raw.h ; then V_PCAP=snoop elif test -r /usr/include/odmi.h ; then # # On AIX, the BPF devices might not yet be present - they're # created the first time libpcap runs after booting. # We check for odmi.h instead. # V_PCAP=bpf elif test -c /dev/bpf0 ; then # check again in case not readable V_PCAP=bpf # # We have BPF, so build valgrindtest with "make test". # VALGRINDTEST=valgrindtest elif test -r /usr/include/sys/dlpi.h ; then V_PCAP=dlpi elif test -c /dev/enet ; then # check again in case not readable V_PCAP=enet elif test -c /dev/nit ; then # check again in case not readable V_PCAP=snit else V_PCAP=null fi AC_MSG_RESULT($V_PCAP) AC_SUBST(VALGRINDTEST) # # Do capture-mechanism-dependent tests. # case "$V_PCAP" in dlpi) # # Needed for common functions used by pcap-[dlpi,libdlpi].c # SSRC="dlpisubs.c" # # Checks for some header files. # AC_CHECK_HEADERS(sys/bufmod.h sys/dlpi_ext.h) # # Checks to see if Solaris has the public libdlpi(3LIB) library. # Note: The existence of /usr/include/libdlpi.h does not mean it is the # public libdlpi(3LIB) version. Before libdlpi was made public, a # private version also existed, which did not have the same APIs. # Due to a gcc bug, the default search path for 32-bit libraries does # not include /lib, we add it explicitly here. # [http://bugs.opensolaris.org/view_bug.do?bug_id=6619485]. # Also, due to the bug above applications that link to libpcap with # libdlpi will have to add "-L/lib" option to "configure". # saved_ldflags=$LDFLAGS LDFLAGS="$LIBS -L/lib" AC_CHECK_LIB(dlpi, dlpi_walk, [ LIBS="-ldlpi $LIBS" V_PCAP=libdlpi AC_DEFINE(HAVE_LIBDLPI,1,[if libdlpi exists]) ], V_PCAP=dlpi) LDFLAGS=$saved_ldflags # # Checks whether is usable, to catch weird SCO # versions of DLPI. # AC_MSG_CHECKING(whether is usable) AC_CACHE_VAL(ac_cv_sys_dlpi_usable, AC_TRY_COMPILE( [ #include #include #include ], [int i = DL_PROMISC_PHYS;], ac_cv_sys_dlpi_usable=yes, ac_cv_sys_dlpi_usable=no)) AC_MSG_RESULT($ac_cv_sys_dlpi_usable) if test $ac_cv_sys_dlpi_usable = no ; then AC_MSG_ERROR( is not usable on this system; it probably has a non-standard DLPI) fi # # Check whether we have a /dev/dlpi device or have multiple devices. # AC_MSG_CHECKING(for /dev/dlpi device) if test -c /dev/dlpi ; then AC_MSG_RESULT(yes) AC_DEFINE(HAVE_DEV_DLPI, 1, [define if you have a /dev/dlpi]) else AC_MSG_RESULT(no) dir="/dev/dlpi" AC_MSG_CHECKING(for $dir directory) if test -d $dir ; then AC_MSG_RESULT(yes) AC_DEFINE_UNQUOTED(PCAP_DEV_PREFIX, "$dir", [/dev/dlpi directory]) else AC_MSG_RESULT(no) fi fi # # This check is for Solaris with DLPI support for passive modes. # See dlpi(7P) for more details. # AC_LBL_DL_PASSIVE_REQ_T ;; linux) # # Do we have the wireless extensions? # AC_CHECK_HEADERS(linux/wireless.h, [], [], [ #include #include #include ]) # # Do we have libnl? # AC_ARG_WITH(libnl, AC_HELP_STRING([--without-libnl],[disable libnl support @<:@default=yes, on Linux, if present@:>@]), with_libnl=$withval,,) if test x$with_libnl != xno ; then have_any_nl="no" incdir=-I/usr/include/libnl3 libnldir= if test x$withval != x ; then libnldir=-L${withval}/lib/.libs incdir=-I${withval}/include fi # # Try libnl 3.x first. # AC_CHECK_LIB(nl-3, nl_socket_alloc, [ # # Yes, we have libnl 3.x. # LIBS="${libnldir} -lnl-genl-3 -lnl-3 $LIBS" AC_DEFINE(HAVE_LIBNL,1,[if libnl exists]) AC_DEFINE(HAVE_LIBNL_3_x,1,[if libnl exists and is version 3.x]) AC_DEFINE(HAVE_LIBNL_NLE,1,[libnl has NLE_FAILURE]) AC_DEFINE(HAVE_LIBNL_SOCKETS,1,[libnl has new-style socket api]) V_INCLS="$V_INCLS ${incdir}" have_any_nl="yes" ],[], ${incdir} ${libnldir} -lnl-genl-3 -lnl-3 ) if test x$have_any_nl = xno ; then # # Try libnl 2.x # AC_CHECK_LIB(nl, nl_socket_alloc, [ # # Yes, we have libnl 2.x. # LIBS="${libnldir} -lnl-genl -lnl $LIBS" AC_DEFINE(HAVE_LIBNL,1,[if libnl exists]) AC_DEFINE(HAVE_LIBNL_2_x,1,[if libnl exists and is version 2.x]) AC_DEFINE(HAVE_LIBNL_NLE,1,[libnl has NLE_FAILURE]) AC_DEFINE(HAVE_LIBNL_SOCKETS,1,[libnl has new-style socket api]) have_any_nl="yes" ]) fi if test x$have_any_nl = xno ; then # # No, we don't; do we have libnl 1.x? # AC_CHECK_LIB(nl, nl_handle_alloc, [ # # Yes. # LIBS="${libnldir} -lnl $LIBS" AC_DEFINE(HAVE_LIBNL,1,[if libnl exists]) have_any_nl="yes" ]) fi if test x$have_any_nl = xno ; then # # No, we don't have libnl at all. # if test x$with_libnl = xyes ; then AC_MSG_ERROR([libnl support requested but libnl not found]) fi fi fi AC_CHECK_HEADERS(linux/ethtool.h,,, [ AC_INCLUDES_DEFAULT #include ]) AC_LBL_TPACKET_STATS AC_LBL_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI ;; bpf) # # Check whether we have the *BSD-style ioctls. # AC_CHECK_HEADERS(net/if_media.h) AC_MSG_CHECKING(whether the system supports zerocopy BPF) AC_TRY_COMPILE( [#include #include #include #include ], [return (BIOCROTZBUF + BPF_BUFMODE_ZBUF);], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_ZEROCOPY_BPF, 1, [define if the system supports zerocopy BPF]) ], AC_MSG_RESULT(no)) # # Check whether we have struct BPF_TIMEVAL. # AC_CHECK_TYPES(struct BPF_TIMEVAL,,, [ #include #include #ifdef HAVE_SYS_IOCCOM_H #include #endif #include ]) ;; dag) # # --with-pcap=dag is the only way to get here, and it means # "DAG support but nothing else" # V_DEFS="$V_DEFS -DDAG_ONLY" xxx_only=yes ;; septel) # # --with-pcap=septel is the only way to get here, and it means # "Septel support but nothing else" # V_DEFS="$V_DEFS -DSEPTEL_ONLY" xxx_only=yes ;; snf) # # --with-pcap=snf is the only way to get here, and it means # "SNF support but nothing else" # V_DEFS="$V_DEFS -DSNF_ONLY" xxx_only=yes ;; null) AC_MSG_WARN(cannot determine packet capture interface) AC_MSG_WARN((see the INSTALL doc for more info)) ;; esac dnl dnl Now figure out how we get a list of interfaces and addresses, dnl if we support capturing. Don't bother if we don't support dnl capturing. dnl if test "$V_PCAP" != null then AC_CHECK_FUNC(getifaddrs,[ # # We have "getifaddrs()"; make sure we have # as well, just in case some platform is really weird. # AC_CHECK_HEADER(ifaddrs.h,[ # # We have the header, so we use "getifaddrs()" to # get the list of interfaces. # V_FINDALLDEVS=fad-getad.c ],[ # # We don't have the header - give up. # XXX - we could also fall back on some other # mechanism, but, for now, this'll catch this # problem so that we can at least try to figure # out something to do on systems with "getifaddrs()" # but without "ifaddrs.h", if there is something # we can do on those systems. # AC_MSG_ERROR([Your system has getifaddrs() but doesn't have a usable .]) ]) ],[ # # Well, we don't have "getifaddrs()", so we have to use # some other mechanism; determine what that mechanism is. # # The first thing we use is the type of capture mechanism, # which is somewhat of a proxy for the OS we're using. # case "$V_PCAP" in dlpi|libdlpi) # # This might be Solaris 8 or later, with # SIOCGLIFCONF, or it might be some other OS # or some older version of Solaris, with # just SIOCGIFCONF. # AC_MSG_CHECKING(whether we have SIOCGLIFCONF) AC_CACHE_VAL(ac_cv_lbl_have_siocglifconf, AC_TRY_COMPILE( [#include #include #include #include #include ], [ioctl(0, SIOCGLIFCONF, (char *)0);], ac_cv_lbl_have_siocglifconf=yes, ac_cv_lbl_have_siocglifconf=no)) AC_MSG_RESULT($ac_cv_lbl_have_siocglifconf) if test $ac_cv_lbl_have_siocglifconf = yes ; then V_FINDALLDEVS=fad-glifc.c else V_FINDALLDEVS=fad-gifc.c fi ;; *) # # Assume we just have SIOCGIFCONF. # (XXX - on at least later Linux kernels, there's # another mechanism, and we should be using that # instead.) # V_FINDALLDEVS=fad-gifc.c ;; esac]) fi ]) AC_MSG_CHECKING(for socklen_t) AC_TRY_COMPILE([ #include #include ], [ socklen_t x; ], have_socklen_t=yes, have_socklen_t=no) if test "x$have_socklen_t" = "xyes"; then AC_DEFINE(HAVE_SOCKLEN_T, 1, [define if socklen_t is defined]) fi AC_MSG_RESULT($have_socklen_t) AC_ARG_ENABLE(ipv6, AC_HELP_STRING([--enable-ipv6],[build IPv6-capable version @<:@default=yes, if getaddrinfo available@:>@]), [], [enable_ipv6=ifavailable]) if test "$enable_ipv6" != "no"; then AC_CHECK_FUNC(getaddrinfo, [ AC_DEFINE(INET6,1,[IPv6]) ], [ if test "$enable_ipv6" != "ifavailable"; then AC_MSG_FAILURE([--enable-ipv6 was given, but getaddrinfo isn't available]) fi ]) fi AC_MSG_CHECKING(whether to build optimizer debugging code) AC_ARG_ENABLE(optimizer-dbg, AC_HELP_STRING([--enable-optimizer-dbg],[build optimizer debugging code])) if test "$enable_optimizer_dbg" = "yes"; then AC_DEFINE(BDEBUG,1,[Enable optimizer debugging]) fi AC_MSG_RESULT(${enable_optimizer_dbg-no}) AC_MSG_CHECKING(whether to build parser debugging code) AC_ARG_ENABLE(yydebug, AC_HELP_STRING([--enable-yydebug],[build parser debugging code])) if test "$enable_yydebug" = "yes"; then AC_DEFINE(YYDEBUG,1,[Enable parser debugging]) fi AC_MSG_RESULT(${enable_yydebug-no}) # Check for Endace DAG card support. AC_ARG_WITH([dag], AC_HELP_STRING([--with-dag@<:@=DIR@:>@],[include Endace DAG support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), [ if test "$withval" = no then # User doesn't want DAG support. want_dag=no elif test "$withval" = yes then # User wants DAG support but hasn't specified a directory. want_dag=yes else # User wants DAG support and has specified a directory, so use the provided value. want_dag=yes dag_root=$withval fi ],[ if test "$V_PCAP" = dag; then # User requested DAG-only libpcap, so we'd better have # the DAG API. want_dag=yes elif test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want DAG support. want_dag=no else # # Use DAG API if present, otherwise don't # want_dag=ifpresent fi ]) AC_ARG_WITH([dag-includes], AC_HELP_STRING([--with-dag-includes=IDIR],[Endace DAG include directory, if not DIR/include]), [ # User wants DAG support and has specified a header directory, so use the provided value. want_dag=yes dag_include_dir=$withval ],[]) AC_ARG_WITH([dag-libraries], AC_HELP_STRING([--with-dag-libraries=LDIR],[Endace DAG library directory, if not DIR/lib]), [ # User wants DAG support and has specified a library directory, so use the provided value. want_dag=yes dag_lib_dir=$withval ],[]) ac_cv_lbl_dag_api=no if test "$want_dag" != no; then AC_MSG_CHECKING([whether we have DAG API headers]) # If necessary, set default paths for DAG API headers and libraries. if test -z "$dag_root"; then dag_root=/usr/local fi if test -z "$dag_include_dir"; then dag_include_dir="$dag_root/include" fi if test -z "$dag_lib_dir"; then dag_lib_dir="$dag_root/lib" fi if test -z "$dag_tools_dir"; then dag_tools_dir="$dag_root/tools" fi if test -r $dag_include_dir/dagapi.h; then ac_cv_lbl_dag_api=yes fi if test "$ac_cv_lbl_dag_api" = yes; then AC_MSG_RESULT([yes ($dag_include_dir)]) V_INCLS="$V_INCLS -I$dag_include_dir" if test $V_PCAP != dag ; then SSRC="$SSRC pcap-dag.c" fi # See if we can find a general version string. # Don't need to save and restore LIBS to prevent -ldag being # included if there's a found-action (arg 3). saved_ldflags=$LDFLAGS LDFLAGS="-L$dag_lib_dir" AC_CHECK_LIB([dag], [dag_attach_stream], [dag_streams="1"], [dag_streams="0"]) AC_CHECK_LIB([dag],[dag_get_erf_types], [ AC_DEFINE(HAVE_DAG_GET_ERF_TYPES, 1, [define if you have dag_get_erf_types()])]) AC_CHECK_LIB([dag],[dag_get_stream_erf_types], [ AC_DEFINE(HAVE_DAG_GET_STREAM_ERF_TYPES, 1, [define if you have dag_get_stream_erf_types()])]) LDFLAGS=$saved_ldflags if test "$dag_streams" = 1; then AC_DEFINE(HAVE_DAG_STREAMS_API, 1, [define if you have streams capable DAG API]) LIBS="$LIBS -ldag" LDFLAGS="$LDFLAGS -L$dag_lib_dir" AC_CHECK_LIB([vdag],[vdag_set_device_info], [ac_dag_have_vdag="1"], [ac_dag_have_vdag="0"]) if test "$ac_dag_have_vdag" = 1; then AC_DEFINE(HAVE_DAG_VDAG, 1, [define if you have vdag_set_device_info()]) LIBS="$LIBS -lpthread" fi fi AC_DEFINE(HAVE_DAG_API, 1, [define if you have the DAG API]) else AC_MSG_RESULT(no) if test "$V_PCAP" = dag; then # User requested "dag" capture type but we couldn't # find the DAG API support. AC_MSG_ERROR([DAG support requested with --with-pcap=dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support]) fi if test "$want_dag" = yes; then # User wanted DAG support but we couldn't find it. AC_MSG_ERROR([DAG support requested with --with-dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support]) fi fi fi AC_ARG_WITH(septel, AC_HELP_STRING([--with-septel@<:@=DIR@:>@],[include Septel support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), [ if test "$withval" = no then want_septel=no elif test "$withval" = yes then want_septel=yes septel_root= else want_septel=yes septel_root=$withval fi ],[ if test "$V_PCAP" = septel; then # User requested Septel-only libpcap, so we'd better have # the Septel API. want_septel=yes elif test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want Septel support. want_septel=no else # # Use Septel API if present, otherwise don't # want_septel=ifpresent fi ]) ac_cv_lbl_septel_api=no if test "$with_septel" != no; then AC_MSG_CHECKING([whether we have Septel API headers]) # If necessary, set default paths for Septel API headers and libraries. if test -z "$septel_root"; then septel_root=$srcdir/../septel fi septel_tools_dir="$septel_root" septel_include_dir="$septel_root/INC" if test -r "$septel_include_dir/msg.h"; then ac_cv_lbl_septel_api=yes fi if test "$ac_cv_lbl_septel_api" = yes; then AC_MSG_RESULT([yes ($septel_include_dir)]) V_INCLS="$V_INCLS -I$septel_include_dir" ADDLOBJS="$ADDLOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" if test "$V_PCAP" != septel ; then SSRC="$SSRC pcap-septel.c" fi AC_DEFINE(HAVE_SEPTEL_API, 1, [define if you have the Septel API]) else AC_MSG_RESULT(no) if test "$V_PCAP" = septel; then # User requested "septel" capture type but # we couldn't find the Septel API support. AC_MSG_ERROR([Septel support requested with --with-pcap=septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support]) fi if test "$want_septel" = yes; then # User wanted Septel support but we couldn't find it. AC_MSG_ERROR([Septel support requested with --with-septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support]) fi fi fi # Check for Myricom SNF support. AC_ARG_WITH([snf], AC_HELP_STRING([--with-snf@<:@=DIR@:>@],[include Myricom SNF support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), [ if test "$withval" = no then # User explicitly doesn't want SNF want_snf=no elif test "$withval" = yes then # User wants SNF support but hasn't specified a directory. want_snf=yes else # User wants SNF support with a specified directory. want_snf=yes snf_root=$withval fi ],[ if test "$V_PCAP" = snf; then # User requested Sniffer-only libpcap, so we'd better have # the Sniffer API. want_snf=yes elif test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want SNF support. want_snf=no else # # Use Sniffer API if present, otherwise don't # want_snf=ifpresent fi ]) AC_ARG_WITH([snf-includes], AC_HELP_STRING([--with-snf-includes=IDIR],[Myricom SNF include directory, if not DIR/include]), [ # User wants SNF with specific header directory want_snf=yes snf_include_dir=$withval ],[]) AC_ARG_WITH([snf-libraries], AC_HELP_STRING([--with-snf-libraries=LDIR],[Myricom SNF library directory, if not DIR/lib]), [ # User wants SNF with specific lib directory want_snf=yes snf_lib_dir=$withval ],[]) ac_cv_lbl_snf_api=no if test "$with_snf" != no; then AC_MSG_CHECKING(whether we have Myricom Sniffer API) # If necessary, set default paths for Sniffer headers and libraries. if test -z "$snf_root"; then snf_root=/opt/snf fi if test -z "$snf_include_dir"; then snf_include_dir="$snf_root/include" fi if test -z "$snf_lib_dir"; then snf_lib_dir="$snf_root/lib" fi if test -f "$snf_include_dir/snf.h"; then # We found a header; make sure we can link with the library saved_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -L$snf_lib_dir" AC_CHECK_LIB([snf], [snf_init], [ac_cv_lbl_snf_api="yes"]) LDFLAGS="$saved_ldflags" if test "$ac_cv_lbl_snf_api" = no; then AC_MSG_ERROR(SNF API cannot correctly be linked; check config.log) fi fi if test "$ac_cv_lbl_snf_api" = yes; then AC_MSG_RESULT([yes ($snf_root)]) V_INCLS="$V_INCLS -I$snf_include_dir" LIBS="$LIBS -lsnf" LDFLAGS="$LDFLAGS -L$snf_lib_dir" if test "$V_PCAP" != snf ; then SSRC="$SSRC pcap-snf.c" fi AC_DEFINE(HAVE_SNF_API, 1, [define if you have the Myricom SNF API]) else AC_MSG_RESULT(no) if test "$want_snf" = yes; then # User requested "snf" capture type but # we couldn't find the Sniffer API support. AC_MSG_ERROR([Myricom Sniffer support requested with --with-pcap=snf, but the Sniffer headers weren't found at $snf_include_dir: make sure the Sniffer support is installed, specify a different path or paths if necessary, or don't request Sniffer support]) fi if test "$want_snf" = yes; then AC_MSG_ERROR([Myricom Sniffer support requested with --with-snf, but the Sniffer headers weren't found at $snf_include_dir: make sure the Sniffer support is installed, specify a different path or paths if necessary, or don't request Sniffer support]) fi fi fi # Check for Riverbed TurboCap support. AC_ARG_WITH([turbocap], AC_HELP_STRING([--with-turbocap@<:@=DIR@:>@],[include Riverbed TurboCap support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), [ if test "$withval" = no then # User explicitly doesn't want TurboCap want_turbocap=no elif test "$withval" = yes then # User wants TurboCap support but hasn't specified a directory. want_turbocap=yes else # User wants TurboCap support with a specified directory. want_turbocap=yes turbocap_root=$withval fi ],[ if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want TurboCap support. want_turbocap=no else # # Use TurboCap API if present, otherwise don't # want_turbocap=ifpresent fi ]) ac_cv_lbl_turbocap_api=no if test "$want_turbocap" != no; then AC_MSG_CHECKING(whether TurboCap is supported) save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" if test ! -z "$turbocap_root"; then TURBOCAP_CFLAGS="-I$turbocap_root/include" TURBOCAP_LIBS="-L$turbocap_root/lib" CFLAGS="$CFLAGS $TURBOCAP_CFLAGS" fi AC_TRY_COMPILE( [ #include ], [ TC_INSTANCE a; TC_PORT b; TC_BOARD c; TC_INSTANCE i; (void)TcInstanceCreateByName("foo", &i); ], ac_cv_lbl_turbocap_api=yes) CFLAGS="$save_CFLAGS" if test $ac_cv_lbl_turbocap_api = yes; then AC_MSG_RESULT(yes) SSRC="$SSRC pcap-tc.c" V_INCLS="$V_INCLS $TURBOCAP_CFLAGS" LIBS="$LIBS $TURBOCAP_LIBS -lTcApi -lpthread -lstdc++" AC_DEFINE(HAVE_TC_API, 1, [define if you have the TurboCap API]) else AC_MSG_RESULT(no) if test "$want_turbocap" = yes; then # User wanted Turbo support but we couldn't find it. AC_MSG_ERROR([TurboCap support requested with --with-turbocap, but the TurboCap headers weren't found: make sure the TurboCap support is installed or don't request TurboCap support]) fi fi fi # # Look for {f}lex. # AC_PROG_LEX if test "$LEX" = ":"; then AC_MSG_ERROR([Neither flex nor lex was found.]) fi # # Make sure {f}lex supports the -P, --header-file, and --nounput flags # and supports processing our scanner.l. # AC_CACHE_CHECK([for capable lex], tcpdump_cv_capable_lex, if $LEX -P pcap_ --header-file=/dev/null --nounput -t $srcdir/scanner.l > /dev/null 2>&1; then tcpdump_cv_capable_lex=yes else tcpdump_cv_capable_lex=insufficient fi) if test $tcpdump_cv_capable_lex = insufficient ; then AC_MSG_ERROR([$LEX is insufficient to compile libpcap. libpcap requires Flex 2.5.31 or later, or a compatible version of lex.]) fi # # Look for yacc/bison/byacc. # AC_PROG_YACC # # Make sure it supports the -p flag and supports processing our # grammar.y. # AC_CACHE_CHECK([for capable yacc/bison], tcpdump_cv_capable_yacc, if $YACC -p pcap_ -o /dev/null $srcdir/grammar.y >/dev/null 2>&1; then tcpdump_cv_capable_yacc=yes else tcpdump_cv_capable_yacc=insufficient fi) if test $tcpdump_cv_capable_yacc = insufficient ; then AC_MSG_ERROR([$YACC is insufficient to compile libpcap. libpcap requires Bison, Berkeley YACC, or another YACC compatible with them.]) fi # # Assume, by default, no support for shared libraries and V7/BSD convention # for man pages (file formats in section 5, miscellaneous info in section 7). # Individual cases can override this. # DYEXT="none" MAN_FILE_FORMATS=5 MAN_MISC_INFO=7 case "$host_os" in aix*) dnl Workaround to enable certain features AC_DEFINE(_SUN,1,[define on AIX to get certain functions]) # # AIX makes it fun to build shared and static libraries, # because they're *both* ".a" archive libraries. We # build the static library for the benefit of the traditional # scheme of building libpcap and tcpdump in subdirectories of # the same directory, with tcpdump statically linked with the # libpcap in question, but we also build a shared library as # "libpcap.shareda" and install *it*, rather than the static # library, as "libpcap.a". # DYEXT="shareda" case "$V_PCAP" in dlpi) # # If we're using DLPI, applications will need to # use /lib/pse.exp if present, as we use the # STREAMS routines. # pseexe="/lib/pse.exp" AC_MSG_CHECKING(for $pseexe) if test -f $pseexe ; then AC_MSG_RESULT(yes) LIBS="-I:$pseexe" fi ;; bpf) # # If we're using BPF, we need "-lodm" and "-lcfg", as # we use them to load the BPF module. # LIBS="-lodm -lcfg" ;; esac ;; darwin*) DYEXT="dylib" V_CCOPT="$V_CCOPT -fno-common" AC_ARG_ENABLE(universal, AC_HELP_STRING([--disable-universal],[don't build universal on OS X])) if test "$enable_universal" != "no"; then case "$host_os" in darwin[0-7].*) # # Pre-Tiger. Build only for 32-bit PowerPC; no # need for any special compiler or linker flags. # ;; darwin8.[0123]*) # # Tiger, prior to Intel support. Build for 32-bit # PowerPC and 64-bit PowerPC, with 32-bit PowerPC # first. (I'm guessing that's what Apple does.) # V_CCOPT="$V_CCOPT -arch ppc -arch ppc64" LDFLAGS="$LDFLAGS -arch ppc -arch ppc64" ;; darwin8.[456]*) # # Tiger, subsequent to Intel support but prior to # x86-64 support. Build for 32-bit PowerPC, 64-bit # PowerPC, and x86, with 32-bit PowerPC first. # (I'm guessing that's what Apple does.) # V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386" LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386" ;; darwin8.*) # # All other Tiger, so subsequent to x86-64 # support. Build for 32-bit PowerPC, 64-bit # PowerPC, x86, and x86-64, and with 32-bit PowerPC # first. (I'm guessing that's what Apple does.) # V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386 -arch x86_64" LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386 -arch x86_64" ;; darwin9.*) # # Leopard. Build for 32-bit PowerPC, 64-bit # PowerPC, x86, and x86-64, with 32-bit PowerPC # first. (That's what Apple does.) # V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386 -arch x86_64" LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386 -arch x86_64" ;; darwin10.*) # # Snow Leopard. Build for x86-64, x86, and # 32-bit PowerPC, with x86-64 first. (That's # what Apple does, even though Snow Leopard # doesn't run on PPC, so PPC libpcap runs under # Rosetta, and Rosetta doesn't support BPF # ioctls, so PPC programs can't do live # captures.) # V_CCOPT="$V_CCOPT -arch x86_64 -arch i386 -arch ppc" LDFLAGS="$LDFLAGS -arch x86_64 -arch i386 -arch ppc" ;; darwin*) # # Post-Snow Leopard. Build for x86-64 and # x86, with x86-64 first. (That's probably what # Apple does, given that Rosetta is gone.) # XXX - update if and when Apple drops support # for 32-bit x86 code. # V_CCOPT="$V_CCOPT -arch x86_64 -arch i386" LDFLAGS="$LDFLAGS -arch x86_64 -arch i386" ;; esac fi ;; hpux9*) AC_DEFINE(HAVE_HPUX9,1,[on HP-UX 9.x]) # # Use System V conventions for man pages. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; hpux10.0*) # # Use System V conventions for man pages. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; hpux10.1*) # # Use System V conventions for man pages. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; hpux*) dnl HPUX 10.20 and above is similar to HPUX 9, but dnl not the same.... dnl dnl XXX - DYEXT should be set to "sl" if this is building dnl for 32-bit PA-RISC, but should be left as "so" for dnl 64-bit PA-RISC or, I suspect, IA-64. AC_DEFINE(HAVE_HPUX10_20_OR_LATER,1,[on HP-UX 10.20 or later]) if test "`uname -m`" = "ia64"; then DYEXT="so" else DYEXT="sl" fi # # "-b" builds a shared library; "+h" sets the soname. # SHLIB_OPT="-b" SONAME_OPT="+h" # # Use System V conventions for man pages. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; irix*) # # Use System V conventions for man pages. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*) DYEXT="so" # # Compiler assumed to be GCC; run-time linker may require a -R # flag. # if test "$libdir" != "/usr/lib"; then V_RFLAGS=-Wl,-R$libdir fi ;; osf*) DYEXT="so" # # Use System V conventions for man pages. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; sinix*) AC_MSG_CHECKING(if SINIX compiler defines sinix) AC_CACHE_VAL(ac_cv_cc_sinix_defined, AC_TRY_COMPILE( [], [int i = sinix;], ac_cv_cc_sinix_defined=yes, ac_cv_cc_sinix_defined=no)) AC_MSG_RESULT($ac_cv_cc_sinix_defined) if test $ac_cv_cc_sinix_defined = no ; then AC_DEFINE(sinix,1,[on sinix]) fi ;; solaris*) AC_DEFINE(HAVE_SOLARIS,1,[On solaris]) DYEXT="so" # # Use System V conventions for man pages. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; esac AC_ARG_ENABLE(shared, AC_HELP_STRING([--enable-shared],[build shared libraries @<:@default=yes, if support available@:>@])) test "x$enable_shared" = "xno" && DYEXT="none" AC_PROG_RANLIB AC_CHECK_TOOL([AR], [ar]) AC_PROG_LN_S AC_SUBST(LN_S) AC_LBL_DEVEL(V_CCOPT) AC_LBL_SOCKADDR_SA_LEN AC_LBL_SOCKADDR_STORAGE AC_LBL_HP_PPA_INFO_T_DL_MODULE_ID_1 AC_LBL_UNALIGNED_ACCESS rm -f net ln -s ${srcdir}/bpf/net net AC_SUBST(V_CCOPT) AC_SUBST(V_DEFS) AC_SUBST(V_FINDALLDEVS) AC_SUBST(V_INCLS) AC_SUBST(V_LEX) AC_SUBST(V_PCAP) AC_SUBST(V_SHLIB_CMD) AC_SUBST(V_SHLIB_OPT) AC_SUBST(V_SONAME_OPT) AC_SUBST(V_RPATH_OPT) AC_SUBST(V_YACC) AC_SUBST(ADDLOBJS) AC_SUBST(ADDLARCHIVEOBJS) AC_SUBST(SSRC) AC_SUBST(DYEXT) AC_SUBST(MAN_FILE_FORMATS) AC_SUBST(MAN_MISC_INFO) AC_ARG_ENABLE([usb], [AC_HELP_STRING([--enable-usb],[enable nusb support @<:@default=yes, if support available@:>@])], [], [enable_usb=yes]) if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want USB support. enable_usb=no fi if test "x$enable_usb" != "xno" ; then dnl check for USB sniffing support AC_MSG_CHECKING(for USB sniffing support) case "$host_os" in linux*) AC_DEFINE(PCAP_SUPPORT_USB, 1, [target host supports USB sniffing]) USB_SRC=pcap-usb-linux.c AC_MSG_RESULT(yes) ac_usb_dev_name=`udevinfo -q name -p /sys/class/usb_device/usbmon 2>/dev/null` if test $? -ne 0 ; then ac_usb_dev_name="usbmon" fi AC_DEFINE_UNQUOTED(LINUX_USB_MON_DEV, "/dev/$ac_usb_dev_name", [path for device for USB sniffing]) AC_MSG_NOTICE(Device for USB sniffing is /dev/$ac_usb_dev_name) # # Do we have a version of available? # If so, we might need it for . # AC_CHECK_HEADERS(linux/compiler.h) if test "$ac_cv_header_linux_compiler_h" = yes; then # # Yes - include it when testing for . # AC_CHECK_HEADERS(linux/usbdevice_fs.h,,,[#include ]) else AC_CHECK_HEADERS(linux/usbdevice_fs.h) fi if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then # # OK, does it define bRequestType? Older versions of the kernel # define fields with names like "requesttype, "request", and # "value", rather than "bRequestType", "bRequest", and # "wValue". # AC_MSG_CHECKING(if usbdevfs_ctrltransfer struct has bRequestType member) AC_CACHE_VAL(ac_cv_usbdevfs_ctrltransfer_has_bRequestType, AC_TRY_COMPILE([ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_BITYPES_H #include #endif #ifdef HAVE_LINUX_COMPILER_H #include #endif #include ], [u_int i = sizeof(((struct usbdevfs_ctrltransfer *)0)->bRequestType)], ac_cv_usbdevfs_ctrltransfer_has_bRequestType=yes, ac_cv_usbdevfs_ctrltransfer_has_bRequestType=no)) AC_MSG_RESULT($ac_cv_usbdevfs_ctrltransfer_has_bRequestType) if test $ac_cv_usbdevfs_ctrltransfer_has_bRequestType = yes ; then AC_DEFINE(HAVE_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE,1, [if struct usbdevfs_ctrltransfer has bRequestType]) fi fi ;; freebsd*) # # This just uses BPF in FreeBSD 8.4 and later; we don't need # to check for anything special for capturing. # AC_MSG_RESULT([yes, in FreeBSD 8.4 and later]) ;; *) AC_MSG_RESULT(no) ;; esac fi AC_SUBST(PCAP_SUPPORT_USB) AC_SUBST(USB_SRC) dnl check for netfilter sniffing support if test "xxx_only" != yes; then AC_MSG_CHECKING(whether the platform could support netfilter sniffing) case "$host_os" in linux*) AC_MSG_RESULT(yes) # # Life's too short to deal with trying to get this to compile # if you don't get the right types defined with # __KERNEL_STRICT_NAMES getting defined by some other include. # # Check whether the includes Just Work. If not, don't turn on # netfilter support. # AC_MSG_CHECKING(whether we can compile the netfilter support) AC_CACHE_VAL(ac_cv_netfilter_can_compile, AC_TRY_COMPILE([ AC_INCLUDES_DEFAULT #include #include #include #include #include #include #include #include ], [], ac_cv_netfilter_can_compile=yes, ac_cv_netfilter_can_compile=no)) AC_MSG_RESULT($ac_cv_netfilter_can_compile) if test $ac_cv_netfilter_can_compile = yes ; then AC_DEFINE(PCAP_SUPPORT_NETFILTER, 1, [target host supports netfilter sniffing]) NETFILTER_SRC=pcap-netfilter-linux.c fi ;; *) AC_MSG_RESULT(no) ;; esac fi AC_SUBST(PCAP_SUPPORT_NETFILTER) AC_SUBST(NETFILTER_SRC) AC_ARG_ENABLE([bluetooth], [AC_HELP_STRING([--enable-bluetooth],[enable Bluetooth support @<:@default=yes, if support available@:>@])], [], [enable_bluetooth=ifsupportavailable]) if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want Bluetooth support. enable_bluetooth=no fi if test "x$enable_bluetooth" != "xno" ; then dnl check for Bluetooth sniffing support case "$host_os" in linux*) AC_CHECK_HEADER(bluetooth/bluetooth.h, [ AC_DEFINE(PCAP_SUPPORT_BT, 1, [target host supports Bluetooth sniffing]) BT_SRC=pcap-bt-linux.c AC_MSG_NOTICE(Bluetooth sniffing is supported) # # OK, does struct sockaddr_hci have an hci_channel # member? # AC_MSG_CHECKING(if struct sockaddr_hci has hci_channel member) AC_CACHE_VAL(ac_cv_lbl_sockaddr_hci_has_hci_channel, AC_TRY_COMPILE( [ #include #include ], [u_int i = sizeof(((struct sockaddr_hci *)0)->hci_channel)], ac_cv_lbl_sockaddr_hci_has_hci_channel=yes, ac_cv_lbl_sockaddr_hci_has_hci_channel=no)) AC_MSG_RESULT($ac_cv_lbl_sockaddr_hci_has_hci_channel) if test $ac_cv_lbl_sockaddr_hci_has_hci_channel = yes ; then AC_DEFINE(SOCKADDR_HCI_HAS_HCI_CHANNEL,, [if struct sockaddr_hci has hci_channel member]) # # OK, is HCI_CHANNEL_MONITOR defined? # AC_MSG_CHECKING(if HCI_CHANNEL_MONITOR is defined) AC_CACHE_VAL(ac_cv_lbl_hci_channel_monitor_is_defined, AC_TRY_COMPILE( [ #include #include ], [u_int i = HCI_CHANNEL_MONITOR], ac_cv_lbl_hci_channel_monitor_is_defined=yes, ac_cv_lbl_hci_channel_monitor_is_defined=no)) AC_MSG_RESULT($ac_cv_lbl_hci_channel_monitor_is_defined) if test $ac_cv_lbl_hci_channel_monitor_is_defined = yes ; then AC_DEFINE(PCAP_SUPPORT_BT_MONITOR,, [target host supports Bluetooth Monitor]) BT_MONITOR_SRC=pcap-bt-monitor-linux.c fi fi ac_lbl_bluetooth_available=yes ], ac_lbl_bluetooth_available=no ) if test "x$ac_lbl_bluetooth_available" == "xno" ; then if test "x$enable_bluetooth" = "xyes" ; then AC_MSG_ERROR(Bluetooth sniffing is not supported; install bluez-lib devel to enable it) else AC_MSG_NOTICE(Bluetooth sniffing is not supported; install bluez-lib devel to enable it) fi fi ;; *) if test "x$enable_bluetooth" = "xyes" ; then AC_MSG_ERROR(no Bluetooth sniffing support implemented for $host_os) else AC_MSG_NOTICE(no Bluetooth sniffing support implemented for $host_os) fi ;; esac AC_SUBST(PCAP_SUPPORT_BT) AC_SUBST(BT_SRC) AC_SUBST(BT_MONITOR_SRC) fi AC_ARG_ENABLE([dbus], [AC_HELP_STRING([--enable-dbus],[enable D-Bus capture support @<:@default=yes, if support available@:>@])], [], [enable_dbus=ifavailable]) if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want D-Bus support. enable_dbus=no fi if test "x$enable_dbus" != "xno"; then if test "x$enable_dbus" = "xyes"; then case "$host_os" in darwin*) # # We don't support D-Bus sniffing on OS X; see # # https://bugs.freedesktop.org/show_bug.cgi?id=74029 # # The user requested it, so fail. # AC_MSG_ERROR([Due to freedesktop.org bug 74029, D-Bus capture support is not available on OS X]) esac else case "$host_os" in darwin*) # # We don't support D-Bus sniffing on OS X; see # # https://bugs.freedesktop.org/show_bug.cgi?id=74029 # # The user dind't explicitly request it, so just # silently refuse to enable it. # enable_dbus="no" ;; esac fi fi if test "x$enable_dbus" != "xno"; then AC_CHECK_PROG([PKGCONFIG], [pkg-config], [pkg-config], [no]) if test "x$PKGCONFIG" != "xno"; then AC_MSG_CHECKING([for D-Bus]) if "$PKGCONFIG" dbus-1; then AC_MSG_RESULT([yes]) DBUS_CFLAGS=`"$PKGCONFIG" --cflags dbus-1` DBUS_LIBS=`"$PKGCONFIG" --libs dbus-1` save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" CFLAGS="$CFLAGS $DBUS_CFLAGS" LIBS="$LIBS $DBUS_LIBS" AC_MSG_CHECKING(whether the D-Bus library defines dbus_connection_read_write) AC_TRY_LINK( [#include #include #include #include ], [return dbus_connection_read_write(NULL, 0);], [ AC_MSG_RESULT([yes]) AC_DEFINE(PCAP_SUPPORT_DBUS, 1, [support D-Bus sniffing]) DBUS_SRC=pcap-dbus.c V_INCLS="$V_INCLS $DBUS_CFLAGS" ], [ AC_MSG_RESULT([no]) if test "x$enable_dbus" = "xyes"; then AC_MSG_ERROR([--enable-dbus was given, but the D-Bus library doesn't define dbus_connection_read_write()]) fi LIBS="$save_LIBS" ]) CFLAGS="$save_CFLAGS" else AC_MSG_RESULT([no]) if test "x$enable_dbus" = "xyes"; then AC_MSG_ERROR([--enable-dbus was given, but the dbus-1 package is not installed]) fi fi fi AC_SUBST(PCAP_SUPPORT_DBUS) AC_SUBST(DBUS_SRC) fi dnl check for hardware timestamp support case "$host_os" in linux*) AC_CHECK_HEADERS([linux/net_tstamp.h]) ;; *) AC_MSG_NOTICE(no hardware timestamp support implemented for $host_os) ;; esac dnl The packet ring capture facility of Linux, described in dnl Documentation/networking/packet_mmap.txt, is not 32/64-bit compatible before dnl version 2.6.27. A 32-bit kernel requires a 32-bit userland, and likewise for dnl 64-bit. The effect of this is that a 32-bit libpcap binary will not run dnl correctly on a 64-bit kernel (the binary will use the wrong offsets into a dnl kernel struct). This problem was solved in Linux 2.6.27. Use dnl --disable-packet-ring whenever a 32-bit application must run on a 64-bit dnl target host, and either the build host or the target host run Linux 2.6.26 dnl or earlier. AC_ARG_ENABLE([packet-ring], [AC_HELP_STRING([--enable-packet-ring],[enable Linux packet ring support @<:@default=yes@:>@])], ,enable_packet_ring=yes) if test "x$enable_packet_ring" != "xno" ; then AC_DEFINE(PCAP_SUPPORT_PACKET_RING, 1, [use Linux packet ring capture if available]) AC_SUBST(PCAP_SUPPORT_PACKET_RING) fi AC_PROG_INSTALL AC_CONFIG_HEADER(config.h) AC_OUTPUT_COMMANDS([if test -f .devel; then echo timestamp > stamp-h cat Makefile-devel-adds >> Makefile make depend fi]) AC_OUTPUT(Makefile pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap) exit 0 libpcap-1.8.1/pcap_dump_ftell.3pcap0000644000026300017510000000323713003771737015361 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_DUMP_FTELL 3PCAP "3 January 2014" .SH NAME pcap_dump_ftell \- get the current file offset for a savefile being written .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B long pcap_dump_ftell(pcap_dumper_t *p); .ft .fi .SH DESCRIPTION .B pcap_dump_ftell() returns the current file position for the ``savefile'', representing the number of bytes written by .B pcap_dump_open() and .BR pcap_dump() . \-1 is returned on error. .SH SEE ALSO pcap(3PCAP), pcap_dump_open(3PCAP), pcap_dump(3PCAP) libpcap-1.8.1/lbl/0000755000026300017510000000000013003775545012040 5ustar mcrmcrlibpcap-1.8.1/lbl/os-aix4.h0000644000026300017510000000232613003771737013477 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. */ /* Prototypes missing in AIX 4.x */ int ffs(int i); libpcap-1.8.1/lbl/os-osf5.h0000644000026300017510000000275313003771737013512 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. */ /* * Prototypes missing in Tru64 UNIX 5.x * XXX - "pcap_snprintf()" and "pcap_vsnprintf()" aren't missing, but you have to * #define the right value to get them defined by . */ int pcap_snprintf(char *, size_t, const char *, ...); int pcap_vsnprintf(char *, size_t, const char *, va_list); int pfopen(char *, int); libpcap-1.8.1/lbl/os-hpux11.h0000644000026300017510000000233113003771737013754 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. */ /* Prototypes missing in HP-UX 11.x */ int ffs(int i); libpcap-1.8.1/lbl/os-solaris2.h0000644000026300017510000000242413003771737014367 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. */ /* Prototypes missing in SunOS 5 */ char *strerror(int); int pcap_snprintf(char *, size_t, const char *, ...); libpcap-1.8.1/lbl/os-sunos4.h0000644000026300017510000001375213003771737014072 0ustar mcrmcr/* * Copyright (c) 1989, 1990, 1993, 1994, 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. */ /* Prototypes missing in SunOS 4 */ #ifdef FILE int _filbuf(FILE *); int _flsbuf(u_char, FILE *); int fclose(FILE *); int fflush(FILE *); int fgetc(FILE *); int fprintf(FILE *, const char *, ...); int fputc(int, FILE *); int fputs(const char *, FILE *); u_int fread(void *, u_int, u_int, FILE *); int fseek(FILE *, long, int); u_int fwrite(const void *, u_int, u_int, FILE *); int pclose(FILE *); void rewind(FILE *); void setbuf(FILE *, char *); int setlinebuf(FILE *); int ungetc(int, FILE *); int vfprintf(FILE *, const char *, ...); int vprintf(const char *, ...); #endif #if __GNUC__ <= 1 int read(int, char *, u_int); int write(int, char *, u_int); #endif long a64l(const char *); #ifdef __STDC__ struct sockaddr; #endif int accept(int, struct sockaddr *, int *); int bind(int, struct sockaddr *, int); int bcmp(const void *, const void *, u_int); void bcopy(const void *, void *, u_int); void bzero(void *, int); int chroot(const char *); int close(int); void closelog(void); int connect(int, struct sockaddr *, int); char *crypt(const char *, const char *); int daemon(int, int); int fchmod(int, int); int fchown(int, int, int); void endgrent(void); void endpwent(void); #ifdef __STDC__ struct ether_addr; #endif struct ether_addr *ether_aton(const char *); int flock(int, int); #ifdef __STDC__ struct stat; #endif int fstat(int, struct stat *); #ifdef __STDC__ struct statfs; #endif int fstatfs(int, struct statfs *); int fsync(int); #ifdef __STDC__ struct timeb; #endif int ftime(struct timeb *); int ftruncate(int, off_t); int getdtablesize(void); long gethostid(void); int gethostname(char *, int); int getopt(int, char * const *, const char *); int getpagesize(void); char *getpass(char *); int getpeername(int, struct sockaddr *, int *); int getpriority(int, int); #ifdef __STDC__ struct rlimit; #endif int getrlimit(int, struct rlimit *); int getsockname(int, struct sockaddr *, int *); int getsockopt(int, int, int, char *, int *); #ifdef __STDC__ struct timeval; struct timezone; #endif int gettimeofday(struct timeval *, struct timezone *); char *getusershell(void); char *getwd(char *); int initgroups(const char *, int); int ioctl(int, int, caddr_t); int iruserok(u_long, int, char *, char *); int isatty(int); int killpg(int, int); int listen(int, int); #ifdef __STDC__ struct utmp; #endif void login(struct utmp *); int logout(const char *); off_t lseek(int, off_t, int); int lstat(const char *, struct stat *); int mkstemp(char *); char *mktemp(char *); int munmap(caddr_t, int); void openlog(const char *, int, int); void perror(const char *); int printf(const char *, ...); int puts(const char *); long random(void); int readlink(const char *, char *, int); #ifdef __STDC__ struct iovec; #endif int readv(int, struct iovec *, int); int recv(int, char *, u_int, int); int recvfrom(int, char *, u_int, int, struct sockaddr *, int *); int rename(const char *, const char *); int rcmd(char **, u_short, char *, char *, char *, int *); int rresvport(int *); int send(int, char *, u_int, int); int sendto(int, char *, u_int, int, struct sockaddr *, int); int setenv(const char *, const char *, int); int seteuid(int); int setpriority(int, int, int); int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); int setpgrp(int, int); void setpwent(void); int setrlimit(int, struct rlimit *); int setsockopt(int, int, int, char *, int); int shutdown(int, int); int sigblock(int); void (*signal (int, void (*) (int))) (int); int sigpause(int); int sigsetmask(int); #ifdef __STDC__ struct sigvec; #endif int sigvec(int, struct sigvec *, struct sigvec*); int pcap_snprintf(char *, size_t, const char *, ...); int socket(int, int, int); int socketpair(int, int, int, int *); int symlink(const char *, const char *); void srandom(int); int sscanf(char *, const char *, ...); int stat(const char *, struct stat *); int statfs(char *, struct statfs *); char *strerror(int); int strcasecmp(const char *, const char *); #ifdef __STDC__ struct tm; #endif int strftime(char *, int, char *, struct tm *); int strncasecmp(const char *, const char *, int); long strtol(const char *, char **, int); void sync(void); void syslog(int, const char *, ...); int system(const char *); long tell(int); time_t time(time_t *); char *timezone(int, int); int tolower(int); int toupper(int); int truncate(char *, off_t); void unsetenv(const char *); int vfork(void); int vsprintf(char *, const char *, ...); int writev(int, struct iovec *, int); #ifdef __STDC__ struct rusage; #endif int utimes(const char *, struct timeval *); #if __GNUC__ <= 1 int wait(int *); pid_t wait3(int *, int, struct rusage *); #endif /* Ugly signal hacking */ #ifdef SIG_ERR #undef SIG_ERR #define SIG_ERR (void (*)(int))-1 #undef SIG_DFL #define SIG_DFL (void (*)(int))0 #undef SIG_IGN #define SIG_IGN (void (*)(int))1 #ifdef KERNEL #undef SIG_CATCH #define SIG_CATCH (void (*)(int))2 #endif #undef SIG_HOLD #define SIG_HOLD (void (*)(int))3 #endif libpcap-1.8.1/lbl/os-osf4.h0000644000026300017510000000253213003771737013504 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. */ /* Prototypes missing in Digital UNIX 4.x */ int pcap_snprintf(char *, size_t, const char *, ...); int pcap_vsnprintf(char *, size_t, const char *, va_list); int pfopen(char *, int); libpcap-1.8.1/lbl/os-aix7.h0000644000026300017510000000232613003771737013502 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. */ /* Prototypes missing in AIX 7.x */ int ffs(int i); libpcap-1.8.1/lbl/os-ultrix4.h0000644000026300017510000000315413003771737014245 0ustar mcrmcr/* * Copyright (c) 1990, 1993, 1994, 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. */ /* Prototypes missing in Ultrix 4 */ int bcmp(const char *, const char *, u_int); void bcopy(const void *, void *, u_int); void bzero(void *, u_int); int getopt(int, char * const *, const char *); #ifdef __STDC__ struct timeval; struct timezone; #endif int gettimeofday(struct timeval *, struct timezone *); int ioctl(int, int, caddr_t); int pfopen(char *, int); int setlinebuf(FILE *); int socket(int, int, int); int strcasecmp(const char *, const char *); libpcap-1.8.1/pcap-nit.c0000644000026300017510000002276213003771737013156 0ustar mcrmcr/* * Copyright (c) 1990, 1991, 1992, 1993, 1994, 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcap-int.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif /* * The chunk size for NIT. This is the amount of buffering * done for read calls. */ #define CHUNKSIZE (2*1024) /* * The total buffer space used by NIT. */ #define BUFSPACE (4*CHUNKSIZE) /* Forwards */ static int nit_setflags(int, int, int, char *); /* * Private data for capturing on NIT devices. */ struct pcap_nit { struct pcap_stat stat; }; static int pcap_stats_nit(pcap_t *p, struct pcap_stat *ps) { struct pcap_nit *pn = p->priv; /* * "ps_recv" counts packets handed to the filter, not packets * that passed the filter. As filtering is done in userland, * this does not include packets dropped because we ran out * of buffer space. * * "ps_drop" presumably counts packets dropped by the socket * because of flow control requirements or resource exhaustion; * it doesn't count packets dropped by the interface driver. * As filtering is done in userland, it counts packets regardless * of whether they would've passed the filter. * * These statistics don't include packets not yet read from the * kernel by libpcap or packets not yet read from libpcap by the * application. */ *ps = pn->stat; return (0); } static int pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct pcap_nit *pn = p->priv; register int cc, n; register u_char *bp, *cp, *ep; register struct nit_hdr *nh; register int caplen; cc = p->cc; if (cc == 0) { cc = read(p->fd, (char *)p->buffer, p->bufsize); if (cc < 0) { if (errno == EWOULDBLOCK) return (0); pcap_snprintf(p->errbuf, sizeof(p->errbuf), "pcap_read: %s", pcap_strerror(errno)); return (-1); } bp = (u_char *)p->buffer; } else bp = p->bp; /* * Loop through each packet. The increment expression * rounds up to the next int boundary past the end of * the previous packet. */ n = 0; ep = bp + cc; while (bp < ep) { /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return -2 to indicate * that we were told to break out of the loop, otherwise * leave the flag set, so that the *next* call will break * out of the loop without having read any packets, and * return the number of packets we've processed so far. */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return (-2); } else { p->cc = ep - bp; p->bp = bp; return (n); } } nh = (struct nit_hdr *)bp; cp = bp + sizeof(*nh); switch (nh->nh_state) { case NIT_CATCH: break; case NIT_NOMBUF: case NIT_NOCLUSTER: case NIT_NOSPACE: pn->stat.ps_drop = nh->nh_dropped; continue; case NIT_SEQNO: continue; default: pcap_snprintf(p->errbuf, sizeof(p->errbuf), "bad nit state %d", nh->nh_state); return (-1); } ++pn->stat.ps_recv; bp += ((sizeof(struct nit_hdr) + nh->nh_datalen + sizeof(int) - 1) & ~(sizeof(int) - 1)); caplen = nh->nh_wirelen; if (caplen > p->snapshot) caplen = p->snapshot; if (bpf_filter(p->fcode.bf_insns, cp, nh->nh_wirelen, caplen)) { struct pcap_pkthdr h; h.ts = nh->nh_timestamp; h.len = nh->nh_wirelen; h.caplen = caplen; (*callback)(user, &h, cp); if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { p->cc = ep - bp; p->bp = bp; return (n); } } } p->cc = 0; return (n); } static int pcap_inject_nit(pcap_t *p, const void *buf, size_t size) { struct sockaddr sa; int ret; memset(&sa, 0, sizeof(sa)); strncpy(sa.sa_data, device, sizeof(sa.sa_data)); ret = sendto(p->fd, buf, size, 0, &sa, sizeof(sa)); if (ret == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", pcap_strerror(errno)); return (-1); } return (ret); } static int nit_setflags(pcap_t *p) { struct nit_ioc nioc; memset(&nioc, 0, sizeof(nioc)); nioc.nioc_typetomatch = NT_ALLTYPES; nioc.nioc_snaplen = p->snapshot; nioc.nioc_bufalign = sizeof(int); nioc.nioc_bufoffset = 0; if (p->opt.buffer_size != 0) nioc.nioc_bufspace = p->opt.buffer_size; else { /* Default buffer size */ nioc.nioc_bufspace = BUFSPACE; } if (p->opt.immediate) { /* * XXX - will this cause packets to be delivered immediately? * XXX - given that this is for SunOS prior to 4.0, do * we care? */ nioc.nioc_chunksize = 0; } else nioc.nioc_chunksize = CHUNKSIZE; if (p->opt.timeout != 0) { nioc.nioc_flags |= NF_TIMEOUT; nioc.nioc_timeout.tv_sec = p->opt.timeout / 1000; nioc.nioc_timeout.tv_usec = (p->opt.timeout * 1000) % 1000000; } if (p->opt.promisc) nioc.nioc_flags |= NF_PROMISC; if (ioctl(p->fd, SIOCSNIT, &nioc) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNIT: %s", pcap_strerror(errno)); return (-1); } return (0); } static int pcap_activate_nit(pcap_t *p) { int fd; struct sockaddr_nit snit; if (p->opt.rfmon) { /* * No monitor mode on SunOS 3.x or earlier (no * Wi-Fi *devices* for the hardware that supported * them!). */ return (PCAP_ERROR_RFMON_NOTSUP); } if (p->snapshot < 96) /* * NIT requires a snapshot length of at least 96. */ p->snapshot = 96; memset(p, 0, sizeof(*p)); p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW); if (fd < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); goto bad; } snit.snit_family = AF_NIT; (void)strncpy(snit.snit_ifname, p->opt.device, NITIFSIZ); if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) { /* * XXX - there's probably a particular bind error that * means "there's no such device" and a particular bind * error that means "that device doesn't support NIT"; * they might be the same error, if they both end up * meaning "NIT doesn't know about that device". */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "bind: %s: %s", snit.snit_ifname, pcap_strerror(errno)); goto bad; } if (nit_setflags(p) < 0) goto bad; /* * NIT supports only ethernets. */ p->linktype = DLT_EN10MB; p->bufsize = BUFSPACE; p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); goto bad; } /* * "p->fd" is a socket, so "select()" should work on it. */ p->selectable_fd = p->fd; /* * This is (presumably) a real Ethernet capture; give it a * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so * that an application can let you choose it, in case you're * capturing DOCSIS traffic that a Cisco Cable Modem * Termination System is putting out onto an Ethernet (it * doesn't put an Ethernet header onto the wire, it puts raw * DOCSIS frames out on the wire inside the low-level * Ethernet framing). */ p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (p->dlt_list != NULL) { p->dlt_list[0] = DLT_EN10MB; p->dlt_list[1] = DLT_DOCSIS; p->dlt_count = 2; } p->read_op = pcap_read_nit; p->inject_op = pcap_inject_nit; p->setfilter_op = install_bpf_program; /* no kernel filtering */ p->setdirection_op = NULL; /* Not implemented. */ p->set_datalink_op = NULL; /* can't change data link type */ p->getnonblock_op = pcap_getnonblock_fd; p->setnonblock_op = pcap_setnonblock_fd; p->stats_op = pcap_stats_nit; return (0); bad: pcap_cleanup_live_common(p); return (PCAP_ERROR); } pcap_t * pcap_create_interface(const char *device _U_, char *ebuf) { pcap_t *p; p = pcap_create_common(ebuf, sizeof (struct pcap_nit)); if (p == NULL) return (NULL); p->activate_op = pcap_activate_nit; return (p); } /* * XXX - there's probably a particular bind error that means "that device * doesn't support NIT"; if so, we should try a bind and use that. */ static int can_be_bound(const char *name _U_) { return (1); } int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { return (pcap_findalldevs_interfaces(alldevsp, errbuf, can_be_bound)); } libpcap-1.8.1/pcap_can_set_rfmon.3pcap0000644000026300017510000000516213003771737016042 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_CAN_SET_RFMON 3PCAP "3 January 2014" .SH NAME pcap_can_set_rfmon \- check whether monitor mode can be set for a not-yet-activated capture handle .SH SYNOPSIS .nf .ft B #include .LP .ft B int pcap_can_set_rfmon(pcap_t *p); .ft .fi .SH DESCRIPTION .B pcap_can_set_rfmon() checks whether monitor mode could be set on a capture handle when the handle is activated. .SH RETURN VALUE .B pcap_can_set_rfmon() returns 0 if monitor mode could not be set, 1 if monitor mode could be set, and a negative value on error. A negative return value indicates what error condition occurred. The possible error values are: .TP .B PCAP_ERROR_NO_SUCH_DEVICE The capture source specified when the handle was created doesn't exist. .TP .B PCAP_ERROR_PERM_DENIED The process doesn't have permission to check whether monitor mode could be supported. .TP .B PCAP_ERROR_ACTIVATED The capture handle has already been activated. .TP .B PCAP_ERROR Another error occurred. .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display a message describing the error. .LP Additional error codes may be added in the future; a program should check for 0, 1, and negative, return codes, and treat all negative return codes as errors. .B pcap_statustostr() can be called, with a warning or error code as an argument, to fetch a message describing the warning or error code. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), pcap_set_rfmon(3PCAP) libpcap-1.8.1/pcap-rpcap.h0000644000026300017510000005205713003771737013476 0ustar mcrmcr/* * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino, CACE Technologies * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __PCAP_RPCAP_H__ #define __PCAP_RPCAP_H__ #include "pcap.h" #include "sockutils.h" /* Needed for some structures (like SOCKET, sockaddr_in) which are used here */ /* * \file pcap-pcap.h * * This file keeps all the new definitions and typedefs that are exported to the user and * that are needed for the RPCAP protocol. * * \warning All the RPCAP functions that are allowed to return a buffer containing * the error description can return max PCAP_ERRBUF_SIZE characters. * However there is no guarantees that the string will be zero-terminated. * Best practice is to define the errbuf variable as a char of size 'PCAP_ERRBUF_SIZE+1' * and to insert manually the termination char at the end of the buffer. This will * guarantee that no buffer overflows occur even if we use the printf() to show * the error on the screen. * * \warning This file declares some typedefs that MUST be of a specific size. * These definitions (i.e. typedefs) could need to be changed on other platforms than * Intel IA32. * * \warning This file defines some structures that are used to transfer data on the network. * Be careful that you compiler MUST not insert padding into these structures * for better alignment. * These structures have been created in order to be correctly aligned to a 32 bits * boundary, but be careful in any case. */ /********************************************************* * * * General definitions / typedefs for the RPCAP protocol * * * *********************************************************/ /* All the following structures and typedef belongs to the Private Documentation */ /* * \addtogroup remote_pri_struct * \{ */ #define RPCAP_DEFAULT_NETPORT "2002" /* Default port on which the RPCAP daemon is waiting for connections. */ /* Default port on which the client workstation is waiting for connections in case of active mode. */ #define RPCAP_DEFAULT_NETPORT_ACTIVE "2003" #define RPCAP_DEFAULT_NETADDR "" /* Default network address on which the RPCAP daemon binds to. */ #define RPCAP_VERSION 0 /* Present version of the RPCAP protocol (0 = Experimental). */ #define RPCAP_TIMEOUT_INIT 90 /* Initial timeout for RPCAP connections (default: 90 sec) */ #define RPCAP_TIMEOUT_RUNTIME 180 /* Run-time timeout for RPCAP connections (default: 3 min) */ #define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */ #define RPCAP_SUSPEND_WRONGAUTH 1 /* If the authentication is wrong, stops 1 sec before accepting a new auth message */ /* * \brief Buffer used by socket functions to send-receive packets. * In case you plan to have messages larger than this value, you have to increase it. */ #define RPCAP_NETBUF_SIZE 64000 /* * \brief Separators used for the host list. * * It is used: * - by the rpcapd daemon, when you types a list of allowed connecting hosts * - by the rpcap in active mode, when the client waits for incoming connections from other hosts */ #define RPCAP_HOSTLIST_SEP " ,;\n\r" /* WARNING: These could need to be changed on other platforms */ typedef unsigned char uint8; /* Provides an 8-bits unsigned integer */ typedef unsigned short uint16; /* Provides a 16-bits unsigned integer */ typedef unsigned int uint32; /* Provides a 32-bits unsigned integer */ typedef int int32; /* Provides a 32-bits integer */ /* * \brief Keeps a list of all the opened connections in the active mode. * * This structure defines a linked list of items that are needed to keep the info required to * manage the active mode. * In other words, when a new connection in active mode starts, this structure is updated so that * it reflects the list of active mode connections currently opened. * This structure is required by findalldevs() and open_remote() to see if they have to open a new * control connection toward the host, or they already have a control connection in place. */ struct activehosts { struct sockaddr_storage host; SOCKET sockctrl; struct activehosts *next; }; /********************************************************* * * * Protocol messages formats * * * *********************************************************/ /* WARNING Take care you compiler does not insert padding for better alignments into these structs */ /* Common header for all the RPCAP messages */ struct rpcap_header { uint8 ver; /* RPCAP version number */ uint8 type; /* RPCAP message type (error, findalldevs, ...) */ uint16 value; /* Message-dependent value (not always used) */ uint32 plen; /* Length of the payload of this RPCAP message */ }; /* Format of the message for the interface description (findalldevs command) */ struct rpcap_findalldevs_if { uint16 namelen; /* Length of the interface name */ uint16 desclen; /* Length of the interface description */ uint32 flags; /* Interface flags */ uint16 naddr; /* Number of addresses */ uint16 dummy; /* Must be zero */ }; /* Format of the message for the address listing (findalldevs command) */ struct rpcap_findalldevs_ifaddr { struct sockaddr_storage addr; /* Network address */ struct sockaddr_storage netmask; /* Netmask for that address */ struct sockaddr_storage broadaddr; /* Broadcast address for that address */ struct sockaddr_storage dstaddr; /* P2P destination address for that address */ }; /* * \brief Format of the message of the connection opening reply (open command). * * This structure transfers over the network some of the values useful on the client side. */ struct rpcap_openreply { int32 linktype; /* Link type */ int32 tzoff; /* Timezone offset */ }; /* Format of the message that starts a remote capture (startcap command) */ struct rpcap_startcapreq { uint32 snaplen; /* Length of the snapshot (number of bytes to capture for each packet) */ uint32 read_timeout; /* Read timeout in milliseconds */ uint16 flags; /* Flags (see RPCAP_STARTCAPREQ_FLAG_xxx) */ uint16 portdata; /* Network port on which the client is waiting at (if 'serveropen') */ }; /* Format of the reply message that devoted to start a remote capture (startcap reply command) */ struct rpcap_startcapreply { int32 bufsize; /* Size of the user buffer allocated by WinPcap; it can be different from the one we chose */ uint16 portdata; /* Network port on which the server is waiting at (passive mode only) */ uint16 dummy; /* Must be zero */ }; /* * \brief Format of the header which encapsulates captured packets when transmitted on the network. * * This message requires the general header as well, since we want to be able to exchange * more information across the network in the future (for example statistics, and kind like that). */ struct rpcap_pkthdr { uint32 timestamp_sec; /* 'struct timeval' compatible, it represents the 'tv_sec' field */ uint32 timestamp_usec; /* 'struct timeval' compatible, it represents the 'tv_usec' field */ uint32 caplen; /* Length of portion present in the capture */ uint32 len; /* Real length this packet (off wire) */ uint32 npkt; /* Ordinal number of the packet (i.e. the first one captured has '1', the second one '2', etc) */ }; /* General header used for the pcap_setfilter() command; keeps just the number of BPF instructions */ struct rpcap_filter { uint16 filtertype; /* type of the filter transferred (BPF instructions, ...) */ uint16 dummy; /* Must be zero */ uint32 nitems; /* Number of items contained into the filter (e.g. BPF instructions for BPF filters) */ }; /* Structure that keeps a single BPF instuction; it is repeated 'ninsn' times according to the 'rpcap_filterbpf' header */ struct rpcap_filterbpf_insn { uint16 code; /* opcode of the instruction */ uint8 jt; /* relative offset to jump to in case of 'true' */ uint8 jf; /* relative offset to jump to in case of 'false' */ int32 k; /* instruction-dependent value */ }; /* Structure that keeps the data required for the authentication on the remote host */ struct rpcap_auth { uint16 type; /* Authentication type */ uint16 dummy; /* Must be zero */ uint16 slen1; /* Length of the first authentication item (e.g. username) */ uint16 slen2; /* Length of the second authentication item (e.g. password) */ }; /* Structure that keeps the statistics about the number of packets captured, dropped, etc. */ struct rpcap_stats { uint32 ifrecv; /* Packets received by the kernel filter (i.e. pcap_stats.ps_recv) */ uint32 ifdrop; /* Packets dropped by the network interface (e.g. not enough buffers) (i.e. pcap_stats.ps_ifdrop) */ uint32 krnldrop; /* Packets dropped by the kernel filter (i.e. pcap_stats.ps_drop) */ uint32 svrcapt; /* Packets captured by the RPCAP daemon and sent on the network */ }; /* Structure that is needed to set sampling parameters */ struct rpcap_sampling { uint8 method; /* Sampling method */ uint8 dummy1; /* Must be zero */ uint16 dummy2; /* Must be zero */ uint32 value; /* Parameter related to the sampling method */ }; /* * Private data for doing a live capture. */ struct pcap_md { struct pcap_stat stat; /* XXX */ int use_bpf; /* using kernel filter */ u_long TotPkts; /* can't overflow for 79 hrs on ether */ u_long TotAccepted; /* count accepted by filter */ u_long TotDrops; /* count of dropped packets */ long TotMissed; /* missed by i/f during this run */ long OrigMissed; /* missed by i/f before this run */ char *device; /* device name */ int timeout; /* timeout for buffering */ int must_clear; /* stuff we must clear when we close */ struct pcap *next; /* list of open pcaps that need stuff cleared on close */ #ifdef linux int sock_packet; /* using Linux 2.0 compatible interface */ int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */ int ifindex; /* interface index of device we're bound to */ int lo_ifindex; /* interface index of the loopback device */ u_int packets_read; /* count of packets read with recvfrom() */ bpf_u_int32 oldmode; /* mode to restore when turning monitor mode off */ u_int tp_version; /* version of tpacket_hdr for mmaped ring */ u_int tp_hdrlen; /* hdrlen of tpacket_hdr for mmaped ring */ #endif /* linux */ #ifdef HAVE_DAG_API #ifdef HAVE_DAG_STREAMS_API u_char *dag_mem_bottom;/* DAG card current memory bottom pointer */ u_char *dag_mem_top; /* DAG card current memory top pointer */ #else /* HAVE_DAG_STREAMS_API */ void *dag_mem_base; /* DAG card memory base address */ u_int dag_mem_bottom; /* DAG card current memory bottom offset */ u_int dag_mem_top; /* DAG card current memory top offset */ #endif /* HAVE_DAG_STREAMS_API */ int dag_fcs_bits; /* Number of checksum bits from link layer */ int dag_offset_flags; /* Flags to pass to dag_offset(). */ int dag_stream; /* DAG stream number */ int dag_timeout; /* timeout specified to pcap_open_live. * Same as in linux above, introduce * generally? */ #endif /* HAVE_DAG_API */ #ifdef HAVE_ZEROCOPY_BPF /* * Zero-copy read buffer -- for zero-copy BPF. 'buffer' above will * alternative between these two actual mmap'd buffers as required. * As there is a header on the front size of the mmap'd buffer, only * some of the buffer is exposed to libpcap as a whole via bufsize; * zbufsize is the true size. zbuffer tracks the current zbuf * associated with buffer so that it can be used to decide which the * next buffer to read will be. */ u_char *zbuf1, *zbuf2, *zbuffer; u_int zbufsize; u_int zerocopy; u_int interrupted; struct timespec firstsel; /* * If there's currently a buffer being actively processed, then it is * referenced here; 'buffer' is also pointed at it, but offset by the * size of the header. */ struct bpf_zbuf_header *bzh; #endif /* HAVE_ZEROCOPY_BPF */ #ifdef HAVE_REMOTE /* * There is really a mess with previous variables, and it seems to me that they are not used * (they are used in pcap_pf.c only). I think we have to start using them. * The meaning is the following: * * - TotPkts: the amount of packets received by the bpf filter, *before* applying the filter * - TotAccepted: the amount of packets that satisfies the filter * - TotDrops: the amount of packet that were dropped into the kernel buffer because of lack of space * - TotMissed: the amount of packets that were dropped by the physical interface; it is basically * the value of the hardware counter into the card. This number is never put to zero, so this number * takes into account the *total* number of interface drops starting from the interface power-on. * - OrigMissed: the amount of packets that were dropped by the interface *when the capture begins*. * This value is used to detect the number of packets dropped by the interface *during the present * capture*, so that (ps_ifdrops= TotMissed - OrigMissed). */ unsigned int TotNetDrops; /* keeps the number of packets that have been dropped by the network */ /* * \brief It keeps the number of packets that have been received by the application. * * Packets dropped by the kernel buffer are not counted in this variable. The variable is always * equal to (TotAccepted - TotDrops), except for the case of remote capture, in which we have also * packets in flight, i.e. that have been transmitted by the remote host, but that have not been * received (yet) from the client. In this case, (TotAccepted - TotDrops - TotNetDrops) gives a * wrong result, since this number does not corresponds always to the number of packet received by * the application. For this reason, in the remote capture we need another variable that takes * into account of the number of packets actually received by the application. */ unsigned int TotCapt; /*! \brief '1' if we're the network client; needed by several functions (like pcap_setfilter() ) to know if they have to use the socket or they have to open the local adapter. */ int rmt_clientside; SOCKET rmt_sockctrl; //!< socket ID of the socket used for the control connection SOCKET rmt_sockdata; //!< socket ID of the socket used for the data connection int rmt_flags; //!< we have to save flags, since they are passed by the pcap_open_live(), but they are used by the pcap_startcapture() int rmt_capstarted; //!< 'true' if the capture is already started (needed to knoe if we have to call the pcap_startcapture() struct pcap_samp rmt_samp; //!< Keeps the parameters related to the sampling process. char *currentfilter; //!< Pointer to a buffer (allocated at run-time) that stores the current filter. Needed when flag PCAP_OPENFLAG_NOCAPTURE_RPCAP is turned on. #endif /* HAVE_REMOTE */ }; /* Messages field coding */ #define RPCAP_MSG_ERROR 1 /* Message that keeps an error notification */ #define RPCAP_MSG_FINDALLIF_REQ 2 /* Request to list all the remote interfaces */ #define RPCAP_MSG_OPEN_REQ 3 /* Request to open a remote device */ #define RPCAP_MSG_STARTCAP_REQ 4 /* Request to start a capture on a remote device */ #define RPCAP_MSG_UPDATEFILTER_REQ 5 /* Send a compiled filter into the remote device */ #define RPCAP_MSG_CLOSE 6 /* Close the connection with the remote peer */ #define RPCAP_MSG_PACKET 7 /* This is a 'data' message, which carries a network packet */ #define RPCAP_MSG_AUTH_REQ 8 /* Message that keeps the authentication parameters */ #define RPCAP_MSG_STATS_REQ 9 /* It requires to have network statistics */ #define RPCAP_MSG_ENDCAP_REQ 10 /* Stops the current capture, keeping the device open */ #define RPCAP_MSG_SETSAMPLING_REQ 11 /* Set sampling parameters */ #define RPCAP_MSG_FINDALLIF_REPLY (128+RPCAP_MSG_FINDALLIF_REQ) /* Keeps the list of all the remote interfaces */ #define RPCAP_MSG_OPEN_REPLY (128+RPCAP_MSG_OPEN_REQ) /* The remote device has been opened correctly */ #define RPCAP_MSG_STARTCAP_REPLY (128+RPCAP_MSG_STARTCAP_REQ) /* The capture is starting correctly */ #define RPCAP_MSG_UPDATEFILTER_REPLY (128+RPCAP_MSG_UPDATEFILTER_REQ) /* The filter has been applied correctly on the remote device */ #define RPCAP_MSG_AUTH_REPLY (128+RPCAP_MSG_AUTH_REQ) /* Sends a message that says 'ok, authorization successful' */ #define RPCAP_MSG_STATS_REPLY (128+RPCAP_MSG_STATS_REQ) /* Message that keeps the network statistics */ #define RPCAP_MSG_ENDCAP_REPLY (128+RPCAP_MSG_ENDCAP_REQ) /* Confirms that the capture stopped successfully */ #define RPCAP_MSG_SETSAMPLING_REPLY (128+RPCAP_MSG_SETSAMPLING_REQ) /* Confirms that the capture stopped successfully */ #define RPCAP_STARTCAPREQ_FLAG_PROMISC 1 /* Enables promiscuous mode (default: disabled) */ #define RPCAP_STARTCAPREQ_FLAG_DGRAM 2 /* Use a datagram (i.e. UDP) connection for the data stream (default: use TCP)*/ #define RPCAP_STARTCAPREQ_FLAG_SERVEROPEN 4 /* The server has to open the data connection toward the client */ #define RPCAP_STARTCAPREQ_FLAG_INBOUND 8 /* Capture only inbound packets (take care: the flag has no effects with promiscuous enabled) */ #define RPCAP_STARTCAPREQ_FLAG_OUTBOUND 16 /* Capture only outbound packets (take care: the flag has no effects with promiscuous enabled) */ #define RPCAP_UPDATEFILTER_BPF 1 /* This code tells us that the filter is encoded with the BPF/NPF syntax */ /* Network error codes */ #define PCAP_ERR_NETW 1 /* Network error */ #define PCAP_ERR_INITTIMEOUT 2 /* The RPCAP initial timeout has expired */ #define PCAP_ERR_AUTH 3 /* Generic authentication error */ #define PCAP_ERR_FINDALLIF 4 /* Generic findalldevs error */ #define PCAP_ERR_NOREMOTEIF 5 /* The findalldevs was ok, but the remote end had no interfaces to list */ #define PCAP_ERR_OPEN 6 /* Generic pcap_open error */ #define PCAP_ERR_UPDATEFILTER 7 /* Generic updatefilter error */ #define PCAP_ERR_GETSTATS 8 /* Generic pcap_stats error */ #define PCAP_ERR_READEX 9 /* Generic pcap_next_ex error */ #define PCAP_ERR_HOSTNOAUTH 10 /* The host is not authorized to connect to this server */ #define PCAP_ERR_REMOTEACCEPT 11 /* Generic pcap_remoteaccept error */ #define PCAP_ERR_STARTCAPTURE 12 /* Generic pcap_startcapture error */ #define PCAP_ERR_ENDCAPTURE 13 /* Generic pcap_endcapture error */ #define PCAP_ERR_RUNTIMETIMEOUT 14 /* The RPCAP run-time timeout has expired */ #define PCAP_ERR_SETSAMPLING 15 /* Error during the settings of sampling parameters */ #define PCAP_ERR_WRONGMSG 16 /* The other end endpoint sent a message which has not been recognized */ #define PCAP_ERR_WRONGVER 17 /* The other end endpoint has a version number that is not compatible with our */ /* * \} * // end of private documentation */ /********************************************************* * * * Exported function prototypes * * * *********************************************************/ int pcap_opensource_remote(pcap_t *p, struct pcap_rmtauth *auth); int pcap_startcapture_remote(pcap_t *fp); void rpcap_createhdr(struct rpcap_header *header, uint8 type, uint16 value, uint32 length); int rpcap_deseraddr(struct sockaddr_storage *sockaddrin, struct sockaddr_storage **sockaddrout, char *errbuf); int rpcap_checkmsg(char *errbuf, SOCKET sock, struct rpcap_header *header, uint8 first, ...); int rpcap_senderror(SOCKET sock, char *error, unsigned short errcode, char *errbuf); int rpcap_sendauth(SOCKET sock, struct pcap_rmtauth *auth, char *errbuf); SOCKET rpcap_remoteact_getsock(const char *host, int *isactive, char *errbuf); #endif libpcap-1.8.1/README.tru640000644000026300017510000000322613003771737013134 0ustar mcrmcrThe following instructions are applicable to Tru64 UNIX (formerly Digital UNIX (formerly DEC OSF/1)) version 4.0, and probably to later versions as well; at least some options apply to Digital UNIX 3.2 - perhaps all do. In order to use kernel packet filtering on this system, you have to configure it in such a way: Kernel configuration -------------------- The packet filtering kernel option must be enabled at kernel installation. If it was not the case, you can rebuild the kernel with "doconfig -c" after adding the following line in the kernel configuration file (/sys/conf/): option PACKETFILTER or use "doconfig" without any arguments to add the packet filter driver option via the kernel option menu (see the system administration documentation for information on how to do this). Device configuration -------------------- Devices used for packet filtering must be created thanks to the following command (executed in the /dev directory): ./MAKEDEV pfilt Interface configuration ----------------------- In order to capture all packets on a network, you may want to allow applications to put the interface on that network into "local copy" mode, so that tcpdump can see packets sent by the host on which it's running as well as packets received by that host, and to put the interface into "promiscuous" mode, so that tcpdump can see packets on the network segment not sent to the host on which it's running, by using the pfconfig(1) command: pfconfig +c +p or allow application to put any interface into "local copy" or "promiscuous" mode by using the command: pfconfig +c +p -a Note: all instructions given require root privileges. libpcap-1.8.1/CHANGES0000644000026300017510000010220213003771737012256 0ustar mcrmcrTuesday, Oct. 25, 2016 mcr@sandelman.ca Summary for 1.8.1 libpcap release Add a target in Makefile.in for Exuberant Ctags use: 'extags'. Rename configure.in to configure.ac: autoconf 2.59 Clean up the name-to-DLT mapping table. Add some newer DLT_ values: IPMI_HPM_2,ZWAVE_R1_R2,ZWAVE_R3,WATTSTOPPER_DLM,ISO_14443,RDS Clarify what the return values are for both success and failure. Many changes to build on windows Check for the "break the loop" condition in the inner loop for TPACKET_V3. Fix handling of packet count in the TPACKET_V3 inner loop: GitHub issue #493. Filter out duplicate looped back CAN frames. Fix the handling of loopback filters for IPv6 packets. Add a link-layer header type for RDS (IEC 62106) groups. Use different intermediate folders for x86 and x64 builds on Windows. On Linux, handle all CAN captures with pcap-linux.c, in cooked mode. Removes the need for the "host-endian" link-layer header type. Compile with '-Wused-but-marked-unused' in devel mode if supported Have separate DLTs for big-endian and host-endian SocketCAN headers. Reflect version.h being renamed to pcap_version.h. Require that version.h be generated: all build procedures we support generate version.h (autoconf, CMake, MSVC)! Properly check for sock_recv() errors. Re-impose some of Winsock's limitations on sock_recv(). Replace sprintf() with pcap_snprintf(). Fix signature of pcap_stats_ex_remote(). Initial cmake support for remote packet capture. Have rpcap_remoteact_getsock() return a SOCKET and supply an "is active" flag. Clean up {DAG, Septel, Myricom SNF}-only builds. Do UTF-16-to-ASCII conversion into the right place. pcap_create_interface() needs the interface name on Linux. Clean up hardware time stamp support: the "any" device does not support any time stamp types. Add support for capturing on FreeBSD usbusN interfaces. Add a LINKTYPE/DLT_ value for FreeBSD USB. Go back to using PCAP_API on Windows. CMake support Add TurboCap support from WinPcap. Recognize 802.1ad nested VLAN tag in vlan filter. Thursday Sep. 3, 2015 guy@alum.mit.edu Summary for 1.7.5 libpcap release Man page cleanups. Add some allocation failure checks. Fix a number of Linux/ucLinux configure/build issues. Fix some memory leaks. Recognize 802.1ad nested VLAN tag in vlan filter. Fix building Bluetooth Linux Monitor support with BlueZ 5.1+ Saturday Jun. 27, 2015 mcr@sandelman.ca Summary for 1.7.4 libpcap release Include fix for GitHub issue #424 -- out of tree builds. Friday Apr. 10, 2015 guy@alum.mit.edu Summary for 1.7.3 libpcap release Work around a Linux bonding driver bug. Thursday Feb. 12, 2015 guy@alum.mit.edu/mcr@sandelman.ca Summary for 1.7.2 libpcap release Support for filtering Geneve encapsulated packets. Generalize encapsulation handling, fixing some bugs. Don't add null addresses to address lists. Add pcap_dump_open_append() to open for appending. Fix the swapping of isochronous descriptors in Linux USB. Attempt to handle TPACKET_V1 with 32-bit userland and 64-bit kernel. Wednesday Nov. 12, 2014 guy@alum.mit.edu/mcr@sandelman.ca Summary for 1.7.0 libpcap release Fix handling of zones for BPF on Solaris new DLT for ZWAVE clarifications for read timeouts. Use BPF extensions in compiled filters, fixing VLAN filters some fixes to compilation without stdint.h EBUSY can now be returned by SNFv3 code. Fix the range checks in BPF loads Various DAG fixes. Various Linux fixes. Monday Aug. 12, 2014 guy@alum.mit.edu Summary for 1.6.2 libpcap release Don't crash on filters testing a non-existent link-layer type field. Fix sending in non-blocking mode on Linux with memory-mapped capture. Fix timestamps when reading pcap-ng files on big-endian machines. Saturday Jul. 19, 2014 mcr@sandelman.ca Summary for 1.6.1 libpcap release some fixes for the any device changes for how --enable-XXX (--enable-sniffing, --enable-can) works Wednesday Jul. 2, 2014 mcr@sandelman.ca Summary for 1.6.0 libpcap release Don't support D-Bus sniffing on OS X fixes for byte order issues with NFLOG captures Handle using cooked mode for DLT_NETLINK in activate_new(). on platforms where you can not capture on down interfaces, do not list them but: do list interfaces which are down, if you can capture on them! Wednesday December 18, 2013 guy@alum.mit.edu Summary for 1.5.3 libpcap release Don't let packets that don't match the current filter get to the application when TPACKET_V3 is used. (GitHub issue #331) Fix handling of pcap_loop()/pcap_dispatch() with a packet count of 0 on some platforms (including Linux with TPACKET_V3). (GitHub issue #333) Work around TPACKET_V3 deficiency that causes packets to be lost when a timeout of 0 is specified. (GitHub issue #335) Man page formatting fixes. Wednesday December 4, 2013 guy@alum.mit.edu Summary for 1.5.2 libpcap release Fix libpcap to work when compiled with TPACKET_V3 support and running on a kernel without TPACKET_V3 support. (GitHub issue #329) Wednesday November 20, 2013 guy@alum.mit.edu Summary for 1.5.1 libpcap release Report an error, rather than crashing, if an IPv6 address is used for link-layer filtering. (Wireshark bug 9376) Wednesday October 30, 2013 guy@alum.mit.edu Summary for 1.5.0 libpcap release TPACKET_V3 support added for Linux Point users to the the-tcpdump-group repository on GitHub rather than the mcr repository Checks added for malloc()/realloc()/etc. failures Fixed build on Solaris 11 Support filtering filtering E1 SS7 traffic on MTP2 layer Annex A Use "ln -s" to link man pages by default Add support for getting nanosecond-resolution time stamps when capturing and reading capture files Many changes to autoconf to deal better with non-GCC compilers added many new DLT types Saturday April 6, 2013 guy@alum.mit.edu Summary for 1.4.0 libpcap release Add netfilter/nfqueue interface. If we don't have support for IPv6 address resolution, support, in filter expressions, what IPv6 stuff we can. Fix pcap-config to include -lpthread if canusb support is present Try to fix "pcap_parse not defined" problems when --without-flex and --without-bison are used when you have Flex and Bison Fix some issues with the pcap_loop man page. Fix pcap_getnonblock() and pcap_setnonblock() to fill in the supplied error message buffer Fix typo that, it appeared, would cause pcap-libdlpi.c not to compile (perhaps systems with libdlpi also have BPF and use that instead) Catch attempts to call pcap_compile() on a non-activated pcap_t Fix crash on Linux with CAN-USB support without usbfs Fix addition of VLAN tags for Linux cooked captures Check for both EOPNOTSUPP and EINVAL after SIOCETHTOOL ioctl, so that the driver can report either one if it doesn't support SIOCETHTOOL Add DLT_INFINIBAND and DLT_SCTP Describe "proto XXX" and "protochain XXX" in the pcap-filter man page Handle either directories, or symlinks to directories, that correspond to interfaces in /sys/class/net Fix handling of VLAN tag insertion to check, on Linux 3.x kernels, for VLAN tag valid flag Clean up some man pages Support libnl3 as well as libnl1 and libnl2 on Linux Fix handling of Bluetooth devices on 3.x Linux kernels Friday March 30, 2012. mcr@sandelman.ca Summary for 1.3.0 libpcap release Handle DLT_PFSYNC in {FreeBSD, other *BSD+Mac OS X, other}. Linux: Don't fail if netfilter isn't enabled in the kernel. Add new link-layer type for NFC Forum LLCP. Put the CANUSB stuff into EXTRA_DIST, so it shows up in the release tarball. Add LINKTYPE_NG40/DLT_NG40. Add DLT_MPEG_2_TS/LINKTYPE_MPEG_2_TS for MPEG-2 transport streams. [PATCH] Fix AIX-3.5 crash with read failure during stress AIX fixes. Introduce --disable-shared configure option. Added initial support for canusb devices. Include the pcap(3PCAP) additions as 1.2.1 changes. many updates to documentation: pcap.3pcap.in Improve 'inbound'/'outbound' capture filters under Linux. Note the cleanup of handling of new DLT_/LINKTYPE_ values. On Lion, don't build for PPC. For mac80211 devices we need to clean up monitor mode on exit. Friday December 9, 2011. guy@alum.mit.edu. Summary for 1.2.1 libpcap release Update README file. Fix typoes in README.linux file. Clean up some compiler warnings. Fix Linux compile problems and tests for ethtool.h. Treat Debian/kFreeBSD and GNU/Hurd as systems with GNU toolchains. Support 802.1 QinQ as a form of VLAN in filters. Treat "carp" as equivalent to "vrrp" in filters. Fix code generated for "ip6 protochain". Add some new link-layer header types. Support capturing NetFilter log messages on Linux. Clean up some error messages. Turn off monitor mode on exit for mac80211 interfaces on Linux. Fix problems turning monitor mode on for non-mac80211 interfaces on Linux. Properly fail if /sys/class/net or /proc/net/dev exist but can't be opened. Fail if pcap_activate() is called on an already-activated pcap_t, and add a test program for that. Fix filtering in pcap-ng files. Don't build for PowerPC on Mac OS X Lion. Simplify handling of new DLT_/LINKTYPE_ values. Expand pcap(3PCAP) man page. Sunday July 24, 2011. mcr@sandelman.ca. Summary for 1.2 libpcap release All of the changes listed below for 1.1.1 and 1.1.2. Changes to error handling for pcap_findalldevs(). Fix the calculation of the frame size in memory-mapped captures. Add a link-layer header type for STANAG 5066 D_PDUs. Add a link-layer type for a variant of 3GPP TS 27.010. Noted real nature of LINKTYPE_ARCNET. Add a link-layer type for DVB-CI. Fix configure-script discovery of VLAN acceleration support. see http://netoptimizer.blogspot.com/2010/09/tcpdump-vs-vlan-tags.html Linux, HP-UX, AIX, NetBSD and OpenBSD compilation/conflict fixes. Protect against including AIX 5.x's having been included. Add DLT_DBUS, for raw D-Bus messages. Treat either EPERM or EACCES as "no soup for you". Changes to permissions on DLPI systems. Add DLT_IEEE802_15_4_NOFCS for 802.15.4 interfaces. Fri. August 6, 2010. guy@alum.mit.edu. Summary for 1.1.2 libpcap release Return DLT_ values, not raw LINKTYPE_ values from pcap_datalink() when reading pcap-ng files Add support for "wlan ra" and "wlan ta", to check the RA and TA of WLAN frames that have them Don't crash if "wlan addr{1,2,3,4}" are used without 802.11 headers Do filtering on USB and Bluetooth capturing On FreeBSD/SPARC64, use -fPIC - it's apparently necessary Check for valid port numbers (fit in a 16-bit unsigned field) in "port" filters Reject attempts to put savefiles into non-blocking mode Check for "no such device" for the "get the media types" ioctl in *BSD Improve error messages from bpf_open(), and let it do the error handling Return more specific errors from pcap_can_set_rfmon(); fix documentation Update description fetching code for FreeBSD, fix code for OpenBSD Ignore /sys/net/dev files if we get ENODEV for them, not just ENXIO; fixes handling of bonding devices on Linux Fix check for a constant 0 argument to BPF_DIV Use the right version of ar when cross-building Free any filter set on a savefile when the savefile is closed Include the CFLAGS setting when configure was run in the compiler flags Add support for 802.15.4 interfaces on Linux Thu. April 1, 2010. guy@alum.mit.edu. Summary for 1.1.1 libpcap release Update CHANGES to reflect more of the changes in 1.1.0. Fix build on RHEL5. Fix shared library build on AIX. Thu. March 11, 2010. ken@netfunctional.ca/guy@alum.mit.edu. Summary for 1.1.0 libpcap release Add SocketCAN capture support Add Myricom SNF API support Update Endace DAG and ERF support Add support for shared libraries on Solaris, HP-UX, and AIX Build, install, and un-install shared libraries by default; don't build/install shared libraries on platforms we don't support Fix building from a directory other than the source directory Fix compiler warnings and builds on some platforms Update config.guess and config.sub Support monitor mode on mac80211 devices on Linux Fix USB memory-mapped capturing on Linux; it requires a new DLT_ value On Linux, scan /sys/class/net for devices if we have it; scan it, or /proc/net/dev if we don't have /sys/class/net, even if we have getifaddrs(), as it'll find interfaces with no addresses Add limited support for reading pcap-ng files Fix BPF driver-loading error handling on AIX Support getting the full-length interface description on FreeBSD In the lexical analyzer, free up any addrinfo structure we got back from getaddrinfo(). Add support for BPF and libdlpi in OpenSolaris (and SXCE) Hyphenate "link-layer" everywhere Add /sys/kernel/debug/usb/usbmon to the list of usbmon locations In pcap_read_linux_mmap(), if there are no frames available, call poll() even if we're in non-blocking mode, so we pick up errors, and check for the errors in question. Note that poll() works on BPF devices is Snow Leopard If an ENXIO or ENETDOWN is received, it may mean the device has gone away. Deal with it. For BPF, raise the default capture buffer size to from 32k to 512k Support ps_ifdrop on Linux Added a bunch of #ifdef directives to make wpcap.dll (WinPcap) compile under cygwin. Changes to Linux mmapped captures. Fix bug where create_ring would fail for particular snaplen and buffer size combinations Update pcap-config so that it handles libpcap requiring additional libraries Add workaround for threadsafeness on Windows Add missing mapping for DLT_ENC <-> LINKTYPE_ENC DLT: Add DLT_CAN_SOCKETCAN DLT: Add Solaris ipnet Don't check for DLT_IPNET if it's not defined Add link-layer types for Fibre Channel FC-2 Add link-layer types for Wireless HART Add link-layer types for AOS Add link-layer types for DECT Autoconf fixes (AIX, HP-UX, OSF/1, Tru64 cleanups) Install headers unconditionally, and include vlan.h/bluetooth.h if enabled Autoconf fixes+cleanup Support enabling/disabling bluetooth (--{en,dis}able-bluetooth) Support disabling SITA support (--without-sita) Return -1 on failure to create packet ring (if supported but creation failed) Fix handling of 'any' device, so that it can be opened, and no longer attempt to open it in Monitor mode Add support for snapshot length for USB Memory-Mapped Interface Fix configure and build on recent Linux kernels Fix memory-mapped Linux capture to support pcap_next() and pcap_next_ex() Fixes for Linux USB capture DLT: Add DLT_LINUX_EVDEV DLT: Add DLT_GSMTAP_UM DLT: Add DLT_GSMTAP_ABIS Mon. October 27, 2008. ken@netfunctional.ca. Summary for 1.0.0 libpcap release Compile with IPv6 support by default Compile with large file support on by default Add pcap-config script, which deals with -I/-L flags for compiling DLT: Add IPMB DLT: Add LAPD DLT: Add AX25 (AX.25 w/KISS header) DLT: Add JUNIPER_ST 802.15.4 support Variable length 802.11 header support X2E data type support SITA ACN Interface support - see README.sita Support for memory-mapped capture on Linux Support for zerocopy BPF on platforms that support it Support for setting buffer size when opening devices Support for setting monitor mode when opening 802.11 devices Better support for dealing with VLAN tagging/stripping on Linux Fix dynamic library support on OSX Return PCAP_ERROR_IFACE_NOT_UP if the interface isn't 'UP', so applications can print better diagnostic information Return PCAP_ERROR_PERM_DENIED if we don't have permission to open a device, so applications can tell the user they need to go play with permissions On Linux, ignore ENETDOWN so we can continue to capture packets if the interface goes down and comes back up again. On Linux, support new tpacket frame headers (2.6.27+) On Mac OS X, add scripts for changing permissions on /dev/bpf* and launchd plist On Solaris, support 'passive mode' on systems that support it Fixes to autoconf and general build environment Man page reorganization + cleanup Autogenerate VERSION numbers better Mon. September 10, 2007. ken@xelerance.com. Summary for 0.9.8 libpcap release Change build process to put public libpcap headers into pcap subir DLT: Add value for IPMI IPMB packets DLT: Add value for u10 Networks boards Require for pf definitions - allows reading of pflog formatted libpcap files on an OS other than where the file was generated Wed. April 25, 2007. ken@xelerance.com. Summary for 0.9.6 libpcap release Put the public libpcap headers into a pcap subdirectory in both the source directory and the target include directory, and have include files at the top-level directory to include those headers, for backwards compatibility. Add Bluetooth support Add USB capturing support on Linux Add support for the binary USB sniffing interface in Linux Add support for new FreeBSD BIOCSDIRECTION ioctl Add additional filter operations for 802.11 frame types Add support for filtering on MTP2 frame types Propagate some changes from the main branch, so the x.9 branch has all the DLT_ and LINKTYPE_ values that the main branch does Reserved a DLT_ and SAVEFILE_ value for PPI (Per Packet Info) encapsulated packets Add LINKTYPE_ for IEEE 802.15.4, with address fields padded as done by Linux drivers Add LINKTYPE_ value corresponding to DLT_IEEE802_16_MAC_CPS. Add DLT for IEEE 802.16 (WiMAX) MAC Common Part Sublayer Add DLT for Bluetooth HCI UART transport layer When building a shared library, build with "-fPIC" on Linux to support x86_64 Link with "$(CC) -shared" rather than "ld -shared" when building a ".so" shared library Add support for autoconf 2.60 Fixes to discard unread packets when changing filters Changes to handle name changes in the DAG library resulting from switching to libtool. Add support for new DAG ERF types. Add an explicit "-ldag" when building the shared library, so the DAG library dependency is explicit. Mac OSX fixes for dealing with "wlt" devices Fixes in add_or_find_if() & pcap_findalldevs() to optimize generating device lists Fixed a bug in pcap_open_live(). The return value of PacketSetHwFilter was not checked. Tue. September 19, 2006. ken@xelerance.com. Summary for 0.9.5 libpcap release Support for LAPD frames with vISDN Support for ERF on channelized T1/E1 cards via DAG API Fix capitalization that caused issues crossc compiling on Linux Better failure detection on PacketGetAdapterNames() Fixes for MPLS packet generation (link layer) OP_PACKET now matches the beginning of the packet, instead of beginning+link-layer Add DLT/LINKTYPE for carrying FRF.16 Multi-link Frame Relay Fix allocation of buffer for list of link-layer types Added a new DLT and LINKTYPE value for ARINC 653 Interpartition Communcation Messages Fixed a typo in a DLT value: it should start with DLT_ and not LINKTYPE_ Redefined DLT_CAN20B and LINKTYPE_CAN20B as #190 (as this is the right value for CAN). Added definition for DLT_A429 and LINKTYPE_A429 as #184. Added a new DLT and LINKTYPE value for CAN v2.0B frames. Add support for DLT_JUNIPER_VP. Don't double-count received packets on Linux systems that support the PACKET_STATISTICS getsockopt() argument on PF_PACKET sockets. Add support for DLT_IEEE802_11 and DLT_IEEE802_11_RADIO link layers in Windows Add support to build libpcap.lib and wpcap.dll under Cygnus and MingW32. Mon. September 5, 2005. ken@xelerance.com. Summary for 0.9.4 libpcap release Support for radiotap on Linux (Mike Kershaw) Fixes for HP-UX Support for additional Juniper link-layer types Fixes for filters on MPLS-encapsulated packets "vlan" filter fixed "pppoed" and "pppoes" filters added; the latter modifies later parts of the filter expression to look at the PPP headers and headers in the PPP payload Tue. July 5, 2005. ken@xelerance.com. Summary for 0.9.3 libpcap release Fixes for compiling on nearly every platform, including improved 64bit support MSDOS Support Add support for sending packets OpenBSD pf format support IrDA capture (Linux only) Tue. March 30, 2004. mcr@sandelman.ottawa.on.ca. Summary for 3.8.3 release Fixed minor problem in gencode.c that would appear on 64-bit platforms. Version number is now sane. Mon. March 29, 2004. mcr@sandelman.ottawa.on.ca. Summary for 3.8.2 release updates for autoconf 2.5 fixes for ppp interfaces for freebsd 4.1 pcap gencode can generate code for 802.11, IEEE1394, and pflog. Wed. November 12, 2003. mcr@sandelman.ottawa.on.ca. Summary for 0.8 release added pcap_findalldevs() Win32 patches from NetGroup, Politecnico di Torino (Italy) OpenBSD pf, DLT_PFLOG added Many changes to ATM support. lookup pcap_lookupnet() Added DLT_ARCNET_LINUX, DLT_ENC, DLT_IEEE802_11_RADIO, DLT_SUNATM, DLT_IP_OVER_FC, DLT_FRELAY, others. Sigh. More AIX wonderfulness. Document updates. Changes to API: pcap_next_ex(), pcap_breakloop(), pcap_dump_flush(), pcap_list_datalinks(), pcap_set_datalink(), pcap_lib_version(), pcap_datalink_val_to_name(), pcap_datalink_name_to_val(), new error returns. Tuesday, February 25, 2003. fenner@research.att.com. 0.7.2 release Support link types that use 802.2 always, never, and sometimes. Don't decrease the size of the BPF buffer from the default. Support frame relay. Handle 32-bit timestamps in DLPI, and pass the right buffer size. Handle Linux systems with modern kernel but without SOL_PACKET in the userland headers. Linux support for ARPHRD_RAWHDLC. Handle 32-bit timestamps in snoop. Support eg (Octane/O2xxx/O3xxx Gigabit) devices. Add new reserved DLT types. Monday October 23, 2001. mcr@sandelman.ottawa.on.ca. Summary for 0.7 release Added pcap_findalldevs() call to get list of interfaces in a MI way. pcap_stats() has been documented as to what its counters mean on each platform. Tuesday January 9, 2001. guy@alum.mit.edu. Summary for 0.6 release New Linux libpcap implementation, which, in 2.2 and later kernels, uses PF_PACKET sockets and supports kernel packet filtering (if compiled into the kernel), and supports the "any" device for capturing on all interfaces. Cleans up promiscuous mode better on pre-2.2 kernels, and has various other fixes (handles 2.4 ARPHRD_IEEE802_TR, handles ISDN devices better, doesn't show duplicate packets on loopback interface, etc.). Fixed HP-UX libpcap implementation to correctly get the PPA for an interface, to allow interfaces to be opened by interface name. libpcap savefiles have system-independent link-layer type values in the header, rather than sometimes platform-dependent DLT_ values, to make it easier to exchange capture files between different OSes. Non-standard capture files produced by some Linux tcpdumps, e.g. the one from Red Hat Linux 6.2 and later, can now be read. Updated autoconf stock files. Filter expressions can filter on VLAN IDs and various OSI protocols, and work on Token Ring (with non-source-routed packets). "pcap_open_dead()" added to allow compiling filter expressions to pcap code without opening a capture device or capture file. Header files fixed to allow use in C++ programs. Removed dependancy on native headers for packet layout. Removed Linux specific headers that were shipped. Security fixes: Strcpy replaced with strlcpy, sprintf replaced with snprintf. Fixed bug that could cause subsequent "pcap_compile()"s to fail erroneously after one compile failed. Assorted other bug fixes. README.aix and README.linux files added to describe platform-specific issues. "getifaddrs()" rather than SIOCGIFCONF used, if available. v0.5 Sat Jun 10 11:09:15 PDT 2000 itojun@iijlab.net - Brought in KAME IPv6/IPsec bpf compiler. - Fixes for NetBSD. - Support added for OpenBSD DLT_LOOP and BSD/OS DLT_C_HDLC (Cisco HDLC), and changes to work around different BSDs having different DLT_ types with the same numeric value. Assar Westerlund - Building outside the source code tree fixed. - Changed to write out time stamps with 32-bit seconds and microseconds fields, regardless of whether those fields are 32 bits or 64 bits in the OS's native "struct timeval". - Changed "pcap_lookupdev()" to dynamically grow the buffer into which the list of interfaces is read as necessary in order to hold the entire list. Greg Troxel - Added a new "pcap_compile_nopcap()", which lets you compile a filter expression into a BPF program without having an open live capture or capture file. v0.4 Sat Jul 25 12:40:09 PDT 1998 - Fix endian problem with DLT_NULL devices. From FreeBSD via Bill Fenner (fenner@parc.xerox.com) - Fix alignment problem with FDDI under DLPI. This was causing core dumps under Solaris. - Added configure options to disable flex and bison. Resulted from a bug report by barnett@grymoire.crd.ge.com (Bruce Barnett). Also added options to disable gcc and to force a particular packet capture type. - Added support for Fore ATM interfaces (qaa and fa) under IRIX. Thanks to John Hawkinson (jhawk@mit.edu) - Change Linux PPP and SLIP to use DLT_RAW since the kernel does not supply any "link layer" data. - Change Linux to use SIOCGIFHWADDR ioctl to determine link layer type. Thanks to Thomas Sailer (sailer@ife.ee.ethz.ch) - Change IRIX PPP to use DLT_RAW since the kernel does not supply any "link layer" data. - Modified to support the new BSD/OS 2.1 PPP and SLIP link layer header formats. - Added some new SGI snoop interface types. Thanks to Steve Alexander (sca@refugee.engr.sgi.com) - Fixes for HP-UX 10.20 (which is similar to HP-UX 9). Thanks to Richard Allen (ra@hp.is) and Steinar Haug (sthaug@nethelp.no) - Fddi supports broadcast as reported by Jeff Macdonald (jeff@iacnet.com). Also correct ieee802 and arcnet. - Determine Linux pcap buffer size at run time or else it might not be big enough for some interface types (e.g. FDDI). Thanks to Jes Sorensen (Jes.Sorensen@cern.ch) - Fix some linux alignment problems. - Document promisc argument to pcap_open_live(). Reported by Ian Marsh (ianm@sics.se) - Support Metricom radio packets under Linux. Thanks to Kevin Lai (laik@gunpowder.stanford.edu) - Bind to interface name under Linux to avoid packets from multiple interfaces on multi-homed hosts. Thanks to Kevin Lai (laik@gunpowder.stanford.edu) - Change L_SET to SEEK_SET for HP-UX. Thanks to Roland Roberts (rroberts@muller.com) - Fixed an uninitialized memory reference found by Kent Vander Velden (graphix@iastate.edu) - Fixed lex pattern for IDs to allow leading digits. As reported by Theo de Raadt (deraadt@cvs.openbsd.org) - Fixed Linux include file problems when using GNU libc. - Ifdef ARPHRD_FDDI since not all versions of the Linux kernel have it. Reported reported by Eric Jacksch (jacksch@tenebris.ca) - Fixed bug in pcap_dispatch() that kept it from returning on packet timeouts. - Changed ISLOOPBACK() macro when IFF_LOOPBACK isn't available to check for "lo" followed by an eos or digit (newer versions of Linux apparently call the loopback "lo" instead of "lo0"). - Fixed Linux networking include files to use ints instead of longs to avoid problems with 64 bit longs on the alpha. Thanks to Cristian Gafton (gafton@redhat.com) v0.3 Sat Nov 30 20:56:27 PST 1996 - Added Linux support. - Fixed savefile bugs. - Solaris x86 fix from Tim Rylance (t.rylance@elsevier.nl) - Add support for bpf kernel port filters. - Remove duplicate atalk protocol table entry. Thanks to Christian Hopps (chopps@water.emich.edu) - Fixed pcap_lookupdev() to ignore nonexistent devices. This was reported to happen under BSD/OS by David Vincenzetti (vince@cryptonet.it) - Avoid solaris compiler warnings. Thanks to Bruce Barnett (barnett@grymoire.crd.ge.com) v0.2.1 Sun Jul 14 03:02:26 PDT 1996 - Fixes for HP-UX 10. Thanks in part to to Thomas Wolfram (wolf@prz.tu-berlin.de) and Rick Jones (raj@hpisrdq.cup.hp.com) - Added support for SINIX. Thanks to Andrej Borsenkow (borsenkow.msk@sni.de) - Fixes for AIX (although this system is not yet supported). Thanks to John Hawkinson (jhawk@mit.edu) - Use autoconf's idea of the top level directory in install targets. Thanks to John Hawkinson. - Add missing autoconf packet capture result message. Thanks to Bill Fenner (fenner@parc.xerox.com) - Fixed padding problems in the pf module. - Fixed some more alignment problems on the alpha. - Added explicit netmask support. Thanks to Steve Nuchia (steve@research.oknet.com) - Fixed to handle raw ip addresses such as 0.0.0.1 without "left justifing" - Add "sca" keyword (for DEC cluster services) as suggested by Terry Kennedy (terry@spcvxa.spc.edu) - Add "atalk" keyword as suggested by John Hawkinson. - Add "igrp" keyword. - Fixed HID definition in grammar.y to be a string, not a value. - Use $CC when checking gcc version. Thanks to Carl Lindberg (carl_lindberg@blacksmith.com) - Removed obsolete reference to pcap_immediate() from the man page. Michael Stolarchuk (mts@terminator.rs.itd.umich.edu) - DLT_NULL has a 4 byte family header. Thanks to Jeffrey Honig (jch@bsdi.com) v0.2 Sun Jun 23 02:28:42 PDT 1996 - Add support for HP-UX. Resulted from code contributed by Tom Murray (tmurray@hpindck.cup.hp.com) and Philippe-Andri Prindeville (philipp@res.enst.fr) - Update INSTALL with a reminder to install include files. Thanks to Mark Andrews (mandrews@aw.sgi.com) - Fix bpf compiler alignment bug on the alpha. - Use autoconf to detect architectures that can't handle misaligned accesses. - Added loopback support for snoop. Resulted from report Steve Alexander (sca@engr.sgi.com) v0.1 Fri Apr 28 18:11:03 PDT 1995 - Fixed compiler and optimizer bugs. The BPF filter engine uses unsigned comparison operators, while the code generator and optimizer assumed signed semantics in several places. Thanks to Charlie Slater (cslater@imatek.com) for pointing this out. - Removed FDDI ifdef's, they aren't really needed. Resulted from report by Gary Veum (veum@boa.gsfc.nasa.gov). - Add pcap-null.c which allows offline use of libpcap on systems that don't support live package capture. This feature resulting from a request from Jan van Oorschot (j.p.m.voorschot@et.tudelft.nl). - Make bpf_compile() reentrant. Fix thanks to Pascal Hennequin (Pascal.Hennequin@hugo.int-evry.fr). - Port to GNU autoconf. - Fix pcap-dlpi.c to work with isdn. Resulted from report by Flemming Johansen (fsj@csd.cri.dk). - Handle multi-digit interface unit numbers (aka ppa's) under dlpi. Resulted from report by Daniel Ehrlich (ehrlich@cse.psu.edu). - Fix pcap-dlpi.c to work in non-promiscuous mode. Resulted from report by Jeff Murphy (jcmurphy@acsu.buffalo.edu). - Add support for "long jumps". Thanks to Jeffrey Mogul (mogul@pa.dec.com). - Fix minor problems when compiling with BDEBUG as noticed by Scott Bertilson (scott@unet.umn.edu). - Declare sys_errlist "const char *const" to avoid problems under FreeBSD. Resulted from report by jher@eden.com. v0.0.6 Fri Apr 28 04:07:13 PDT 1995 - Add missing variable declaration missing from 0.0.6 v0.0.5 Fri Apr 28 00:22:21 PDT 1995 - Workaround for problems when pcap_read() returns 0 due to the timeout expiring. v0.0.4 Thu Apr 20 20:41:48 PDT 1995 - Change configuration to not use gcc v2 flags with gcc v1. - Fixed a bug in pcap_next(); if pcap_dispatch() returns 0, pcap_next() should also return 0. Thanks to Richard Stevens (rstevens@noao.edu). - Fixed configure to test for snoop before dlpi to avoid problems under IRIX 5. Thanks to J. Eric Townsend (jet@abulafia.genmagic.com). - Hack around deficiency in Ultrix's make. - Fix two bugs related to the Solaris pre-5.3.2 bufmod bug; handle savefiles that have more than snapshot bytes of data in them (so we can read old savefiles) and avoid writing such files. - Added checkioctl which is used with gcc to check that the "fixincludes" script has been run. v0.0.3 Tue Oct 18 18:13:46 PDT 1994 - Fixed configure to test for snoop before dlpi to avoid problems under IRIX 5. Thanks to J. Eric Townsend (jet@abulafia.genmagic.com). v0.0.2 Wed Oct 12 20:56:37 PDT 1994 - Implement timeout in the dlpi pcap_open_live(). Thanks to Richard Stevens. - Determine pcap link type from dlpi media type. Resulted from report by Mahesh Jethanandani (mahesh@npix.com). v0.0.1 Fri Jun 24 14:50:57 PDT 1994 - Fixed bug in nit_setflags() in pcap-snit.c. The streams ioctl timeout wasn't being initialized sometimes resulting in an "NIOCSFLAGS: Invalid argument" error under OSF/1. Reported by Matt Day (mday@artisoft.com) and Danny Mitzel (dmitzel@whitney.hitc.com). - Turn on FDDI support by default. v0.0 Mon Jun 20 19:20:16 PDT 1994 - Initial release. - Fixed bug with greater/less keywords, reported by Mark Andrews (mandrews@alias.com). - Fix bug where '|' was defined as BPF_AND instead of BPF_OR, reported by Elan Amir (elan@leeb.cs.berkeley.edu). - Machines with little-endian byte ordering are supported thanks to Jeff Mogul. - Add hack for version 2.3 savefiles which don't have caplen and len swapped thanks to Vern Paxson. - Added "&&" and "||" aliases for "and" and "or" thanks to Vern Paxson. - Added length, inbound and outbound keywords. libpcap-1.8.1/pcap-netfilter-linux.c0000644000026300017510000004423013003771737015507 0ustar mcrmcr/* * Copyright (c) 2011 Jakub Zawadzki * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcap-int.h" #ifdef NEED_STRERROR_H #include "strerror.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* NOTE: if your program drops privilages after pcap_activate() it WON'T work with nfqueue. * It took me quite some time to debug ;/ * * Sending any data to nfnetlink socket requires CAP_NET_ADMIN privilages, * and in nfqueue we need to send verdict reply after recving packet. * * In tcpdump you can disable dropping privilages with -Z root */ #include "pcap-netfilter-linux.h" #define HDR_LENGTH (NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg)))) #define NFLOG_IFACE "nflog" #define NFQUEUE_IFACE "nfqueue" typedef enum { OTHER = -1, NFLOG, NFQUEUE } nftype_t; /* * Private data for capturing on Linux netfilter sockets. */ struct pcap_netfilter { u_int packets_read; /* count of packets read with recvfrom() */ u_int packets_nobufs; /* ENOBUFS counter */ }; static int nfqueue_send_verdict(const pcap_t *handle, u_int16_t group_id, u_int32_t id, u_int32_t verdict); static int netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_netfilter *handlep = handle->priv; const unsigned char *buf; int count = 0; int len; /* ignore interrupt system call error */ do { len = recv(handle->fd, handle->buffer, handle->bufsize, 0); if (handle->break_loop) { handle->break_loop = 0; return -2; } if(errno == ENOBUFS) handlep->packets_nobufs++; } while ((len == -1) && (errno == EINTR || errno == ENOBUFS)); if (len < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s", errno, pcap_strerror(errno)); return -1; } buf = (unsigned char *)handle->buffer; while ((u_int)len >= NLMSG_SPACE(0)) { const struct nlmsghdr *nlh = (const struct nlmsghdr *) buf; u_int32_t msg_len; nftype_t type = OTHER; if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || (u_int)len < nlh->nlmsg_len) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %d) (nlmsg_len: %u)", len, nlh->nlmsg_len); return -1; } if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG && NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET) type = NFLOG; else if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_QUEUE && NFNL_MSG_TYPE(nlh->nlmsg_type) == NFQNL_MSG_PACKET) type = NFQUEUE; if (type != OTHER) { const unsigned char *payload = NULL; struct pcap_pkthdr pkth; const struct nfgenmsg *nfg = NULL; int id = 0; if (handle->linktype != DLT_NFLOG) { const struct nfattr *payload_attr = NULL; if (nlh->nlmsg_len < HDR_LENGTH) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len); return -1; } nfg = NLMSG_DATA(nlh); if (nlh->nlmsg_len > HDR_LENGTH) { struct nfattr *attr = NFM_NFA(nfg); int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH); while (NFA_OK(attr, attr_len)) { if (type == NFQUEUE) { switch (NFA_TYPE(attr)) { case NFQA_PACKET_HDR: { const struct nfqnl_msg_packet_hdr *pkt_hdr = (const struct nfqnl_msg_packet_hdr *) NFA_DATA(attr); id = ntohl(pkt_hdr->packet_id); break; } case NFQA_PAYLOAD: payload_attr = attr; break; } } else if (type == NFLOG) { switch (NFA_TYPE(attr)) { case NFULA_PAYLOAD: payload_attr = attr; break; } } attr = NFA_NEXT(attr, attr_len); } } if (payload_attr) { payload = NFA_DATA(payload_attr); pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr); } } else { payload = NLMSG_DATA(nlh); pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr)); } if (payload) { /* pkth.caplen = min (payload_len, handle->snapshot); */ gettimeofday(&pkth.ts, NULL); if (handle->fcode.bf_insns == NULL || bpf_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen)) { handlep->packets_read++; callback(user, &pkth, payload); count++; } } if (type == NFQUEUE) { /* XXX, possible responses: NF_DROP, NF_ACCEPT, NF_STOLEN, NF_QUEUE, NF_REPEAT, NF_STOP */ /* if type == NFQUEUE, handle->linktype is always != DLT_NFLOG, so nfg is always initialized to NLMSG_DATA(nlh). */ if (nfg != NULL) nfqueue_send_verdict(handle, ntohs(nfg->res_id), id, NF_ACCEPT); } } msg_len = NLMSG_ALIGN(nlh->nlmsg_len); if (msg_len > (u_int)len) msg_len = (u_int)len; len -= msg_len; buf += msg_len; } return count; } static int netfilter_set_datalink(pcap_t *handle, int dlt) { handle->linktype = dlt; return 0; } static int netfilter_stats_linux(pcap_t *handle, struct pcap_stat *stats) { struct pcap_netfilter *handlep = handle->priv; stats->ps_recv = handlep->packets_read; stats->ps_drop = handlep->packets_nobufs; stats->ps_ifdrop = 0; return 0; } static int netfilter_inject_linux(pcap_t *handle, const void *buf, size_t size) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on netfilter devices"); return (-1); } struct my_nfattr { u_int16_t nfa_len; u_int16_t nfa_type; void *data; }; static int netfilter_send_config_msg(const pcap_t *handle, u_int16_t msg_type, int ack, u_int8_t family, u_int16_t res_id, const struct my_nfattr *mynfa) { char buf[1024] __attribute__ ((aligned)); struct nlmsghdr *nlh = (struct nlmsghdr *) buf; struct nfgenmsg *nfg = (struct nfgenmsg *) (buf + sizeof(struct nlmsghdr)); struct sockaddr_nl snl; static unsigned int seq_id; if (!seq_id) seq_id = time(NULL); ++seq_id; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg)); nlh->nlmsg_type = msg_type; nlh->nlmsg_flags = NLM_F_REQUEST | (ack ? NLM_F_ACK : 0); nlh->nlmsg_pid = 0; /* to kernel */ nlh->nlmsg_seq = seq_id; nfg->nfgen_family = family; nfg->version = NFNETLINK_V0; nfg->res_id = htons(res_id); if (mynfa) { struct nfattr *nfa = (struct nfattr *) (buf + NLMSG_ALIGN(nlh->nlmsg_len)); nfa->nfa_type = mynfa->nfa_type; nfa->nfa_len = NFA_LENGTH(mynfa->nfa_len); memcpy(NFA_DATA(nfa), mynfa->data, mynfa->nfa_len); nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len) + NFA_ALIGN(nfa->nfa_len); } memset(&snl, 0, sizeof(snl)); snl.nl_family = AF_NETLINK; if (sendto(handle->fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *) &snl, sizeof(snl)) == -1) return -1; if (!ack) return 0; /* waiting for reply loop */ do { socklen_t addrlen = sizeof(snl); int len; /* ignore interrupt system call error */ do { len = recvfrom(handle->fd, buf, sizeof(buf), 0, (struct sockaddr *) &snl, &addrlen); } while ((len == -1) && (errno == EINTR)); if (len <= 0) return len; if (addrlen != sizeof(snl) || snl.nl_family != AF_NETLINK) { errno = EINVAL; return -1; } nlh = (struct nlmsghdr *) buf; if (snl.nl_pid != 0 || seq_id != nlh->nlmsg_seq) /* if not from kernel or wrong sequence skip */ continue; while ((u_int)len >= NLMSG_SPACE(0) && NLMSG_OK(nlh, len)) { if (nlh->nlmsg_type == NLMSG_ERROR || (nlh->nlmsg_type == NLMSG_DONE && nlh->nlmsg_flags & NLM_F_MULTI)) { if (nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsgerr))) { errno = EBADMSG; return -1; } errno = -(*((int *)NLMSG_DATA(nlh))); return (errno == 0) ? 0 : -1; } nlh = NLMSG_NEXT(nlh, len); } } while (1); return -1; /* never here */ } static int nflog_send_config_msg(const pcap_t *handle, u_int8_t family, u_int16_t group_id, const struct my_nfattr *mynfa) { return netfilter_send_config_msg(handle, (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG, 1, family, group_id, mynfa); } static int nflog_send_config_cmd(const pcap_t *handle, u_int16_t group_id, u_int8_t cmd, u_int8_t family) { struct nfulnl_msg_config_cmd msg; struct my_nfattr nfa; msg.command = cmd; nfa.data = &msg; nfa.nfa_type = NFULA_CFG_CMD; nfa.nfa_len = sizeof(msg); return nflog_send_config_msg(handle, family, group_id, &nfa); } static int nflog_send_config_mode(const pcap_t *handle, u_int16_t group_id, u_int8_t copy_mode, u_int32_t copy_range) { struct nfulnl_msg_config_mode msg; struct my_nfattr nfa; msg.copy_range = htonl(copy_range); msg.copy_mode = copy_mode; nfa.data = &msg; nfa.nfa_type = NFULA_CFG_MODE; nfa.nfa_len = sizeof(msg); return nflog_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); } static int nfqueue_send_verdict(const pcap_t *handle, u_int16_t group_id, u_int32_t id, u_int32_t verdict) { struct nfqnl_msg_verdict_hdr msg; struct my_nfattr nfa; msg.id = htonl(id); msg.verdict = htonl(verdict); nfa.data = &msg; nfa.nfa_type = NFQA_VERDICT_HDR; nfa.nfa_len = sizeof(msg); return netfilter_send_config_msg(handle, (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_VERDICT, 0, AF_UNSPEC, group_id, &nfa); } static int nfqueue_send_config_msg(const pcap_t *handle, u_int8_t family, u_int16_t group_id, const struct my_nfattr *mynfa) { return netfilter_send_config_msg(handle, (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG, 1, family, group_id, mynfa); } static int nfqueue_send_config_cmd(const pcap_t *handle, u_int16_t group_id, u_int8_t cmd, u_int16_t pf) { struct nfqnl_msg_config_cmd msg; struct my_nfattr nfa; msg.command = cmd; msg.pf = htons(pf); nfa.data = &msg; nfa.nfa_type = NFQA_CFG_CMD; nfa.nfa_len = sizeof(msg); return nfqueue_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); } static int nfqueue_send_config_mode(const pcap_t *handle, u_int16_t group_id, u_int8_t copy_mode, u_int32_t copy_range) { struct nfqnl_msg_config_params msg; struct my_nfattr nfa; msg.copy_range = htonl(copy_range); msg.copy_mode = copy_mode; nfa.data = &msg; nfa.nfa_type = NFQA_CFG_PARAMS; nfa.nfa_len = sizeof(msg); return nfqueue_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); } static int netfilter_activate(pcap_t* handle) { const char *dev = handle->opt.device; unsigned short groups[32]; int group_count = 0; nftype_t type = OTHER; int i; if (strncmp(dev, NFLOG_IFACE, strlen(NFLOG_IFACE)) == 0) { dev += strlen(NFLOG_IFACE); type = NFLOG; } else if (strncmp(dev, NFQUEUE_IFACE, strlen(NFQUEUE_IFACE)) == 0) { dev += strlen(NFQUEUE_IFACE); type = NFQUEUE; } if (type != OTHER && *dev == ':') { dev++; while (*dev) { long int group_id; char *end_dev; if (group_count == 32) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Maximum 32 netfilter groups! dev: %s", handle->opt.device); return PCAP_ERROR; } group_id = strtol(dev, &end_dev, 0); if (end_dev != dev) { if (group_id < 0 || group_id > 65535) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Netfilter group range from 0 to 65535 (got %ld)", group_id); return PCAP_ERROR; } groups[group_count++] = (unsigned short) group_id; dev = end_dev; } if (*dev != ',') break; dev++; } } if (type == OTHER || *dev) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get netfilter group(s) index from %s", handle->opt.device); return PCAP_ERROR; } /* if no groups, add default: 0 */ if (!group_count) { groups[0] = 0; group_count = 1; } /* Initialize some components of the pcap structure. */ handle->bufsize = 128 + handle->snapshot; handle->offset = 0; handle->read_op = netfilter_read_linux; handle->inject_op = netfilter_inject_linux; handle->setfilter_op = install_bpf_program; /* no kernel filtering */ handle->setdirection_op = NULL; handle->set_datalink_op = netfilter_set_datalink; handle->getnonblock_op = pcap_getnonblock_fd; handle->setnonblock_op = pcap_setnonblock_fd; handle->stats_op = netfilter_stats_linux; /* Create netlink socket */ handle->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); if (handle->fd < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s", errno, pcap_strerror(errno)); return PCAP_ERROR; } if (type == NFLOG) { handle->linktype = DLT_NFLOG; handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); if (handle->dlt_list != NULL) { handle->dlt_list[0] = DLT_NFLOG; handle->dlt_list[1] = DLT_IPV4; handle->dlt_count = 2; } } else handle->linktype = DLT_IPV4; handle->buffer = malloc(handle->bufsize); if (!handle->buffer) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", pcap_strerror(errno)); goto close_fail; } if (type == NFLOG) { if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_CFG_CMD_PF_UNBIND: %s", pcap_strerror(errno)); goto close_fail; } if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_BIND, AF_INET) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_CFG_CMD_PF_BIND: %s", pcap_strerror(errno)); goto close_fail; } /* Bind socket to the nflog groups */ for (i = 0; i < group_count; i++) { if (nflog_send_config_cmd(handle, groups[i], NFULNL_CFG_CMD_BIND, AF_UNSPEC) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't listen on group group index: %s", pcap_strerror(errno)); goto close_fail; } if (nflog_send_config_mode(handle, groups[i], NFULNL_COPY_PACKET, handle->snapshot) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_COPY_PACKET: %s", pcap_strerror(errno)); goto close_fail; } } } else { if (nfqueue_send_config_cmd(handle, 0, NFQNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFQNL_CFG_CMD_PF_UNBIND: %s", pcap_strerror(errno)); goto close_fail; } if (nfqueue_send_config_cmd(handle, 0, NFQNL_CFG_CMD_PF_BIND, AF_INET) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFQNL_CFG_CMD_PF_BIND: %s", pcap_strerror(errno)); goto close_fail; } /* Bind socket to the nfqueue groups */ for (i = 0; i < group_count; i++) { if (nfqueue_send_config_cmd(handle, groups[i], NFQNL_CFG_CMD_BIND, AF_UNSPEC) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't listen on group group index: %s", pcap_strerror(errno)); goto close_fail; } if (nfqueue_send_config_mode(handle, groups[i], NFQNL_COPY_PACKET, handle->snapshot) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFQNL_COPY_PACKET: %s", pcap_strerror(errno)); goto close_fail; } } } if (handle->opt.rfmon) { /* * Monitor mode doesn't apply to netfilter devices. */ pcap_cleanup_live_common(handle); return PCAP_ERROR_RFMON_NOTSUP; } if (handle->opt.buffer_size != 0) { /* * Set the socket buffer size to the specified value. */ if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, &handle->opt.buffer_size, sizeof(handle->opt.buffer_size)) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SO_RCVBUF: %s", pcap_strerror(errno)); goto close_fail; } } handle->selectable_fd = handle->fd; return 0; close_fail: pcap_cleanup_live_common(handle); return PCAP_ERROR; } pcap_t * netfilter_create(const char *device, char *ebuf, int *is_ours) { const char *cp; pcap_t *p; /* Does this look like an netfilter device? */ cp = strrchr(device, '/'); if (cp == NULL) cp = device; /* Does it begin with NFLOG_IFACE or NFQUEUE_IFACE? */ if (strncmp(cp, NFLOG_IFACE, sizeof NFLOG_IFACE - 1) == 0) cp += sizeof NFLOG_IFACE - 1; else if (strncmp(cp, NFQUEUE_IFACE, sizeof NFQUEUE_IFACE - 1) == 0) cp += sizeof NFQUEUE_IFACE - 1; else { /* Nope, doesn't begin with NFLOG_IFACE nor NFQUEUE_IFACE */ *is_ours = 0; return NULL; } /* * Yes - is that either the end of the name, or is it followed * by a colon? */ if (*cp != ':' && *cp != '\0') { /* Nope */ *is_ours = 0; return NULL; } /* OK, it's probably ours. */ *is_ours = 1; p = pcap_create_common(ebuf, sizeof (struct pcap_netfilter)); if (p == NULL) return (NULL); p->activate_op = netfilter_activate; return (p); } int netfilter_findalldevs(pcap_if_t **alldevsp, char *err_str) { int sock; sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); if (sock < 0) { /* if netlink is not supported this is not fatal */ if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) return 0; pcap_snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't open netlink socket %d:%s", errno, pcap_strerror(errno)); return -1; } close(sock); if (pcap_add_if(alldevsp, NFLOG_IFACE, 0, "Linux netfilter log (NFLOG) interface", err_str) < 0) return -1; if (pcap_add_if(alldevsp, NFQUEUE_IFACE, 0, "Linux netfilter queue (NFQUEUE) interface", err_str) < 0) return -1; return 0; } libpcap-1.8.1/savefile.c0000644000026300017510000003213613003771737013235 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. * * savefile.c - supports offline use of tcpdump * Extraction/creation by Jeffrey Mogul, DECWRL * Modified by Steve McCanne, LBL. * * Used to save the received packet headers, after filtering, to * a file, and then read them later. * The first record in the file contains saved values for the machine * dependent values so we can print the dump file on any architecture. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef _WIN32 #include #else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_BITYPES_H #include #endif #include #endif /* _WIN32 */ #include #include #include #include #include #include "pcap-int.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #include "sf-pcap.h" #include "sf-pcap-ng.h" #ifdef _WIN32 /* * These aren't exported on Windows, because they would only work if both * WinPcap and the code using it were to use the Universal CRT; otherwise, * a FILE structure in WinPcap and a FILE structure in the code using it * could be different if they're using different versions of the C runtime. * * Instead, pcap/pcap.h defines them as macros that wrap the hopen versions, * with the wrappers calling _fileno() and _get_osfhandle() themselves, * so that they convert the appropriate CRT version's FILE structure to * a HANDLE (which is OS-defined, not CRT-defined, and is part of the Win32 * and Win64 ABIs). */ static pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *); static pcap_t *pcap_fopen_offline(FILE *, char *); #endif /* * Setting O_BINARY on DOS/Windows is a bit tricky */ #if defined(_WIN32) #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) #elif defined(MSDOS) #if defined(__HIGHC__) #define SET_BINMODE(f) setmode(f, O_BINARY) #else #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) #endif #endif static int sf_getnonblock(pcap_t *p, char *errbuf) { /* * This is a savefile, not a live capture file, so never say * it's in non-blocking mode. */ return (0); } static int sf_setnonblock(pcap_t *p, int nonblock, char *errbuf) { /* * This is a savefile, not a live capture file, so reject * requests to put it in non-blocking mode. (If it's a * pipe, it could be put in non-blocking mode, but that * would significantly complicate the code to read packets, * as it would have to handle reading partial packets and * keeping the state of the read.) */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Savefiles cannot be put into non-blocking mode"); return (-1); } static int sf_stats(pcap_t *p, struct pcap_stat *ps) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Statistics aren't available from savefiles"); return (-1); } #ifdef _WIN32 static struct pcap_stat * sf_stats_ex(pcap_t *p, int *size) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Statistics aren't available from savefiles"); return (NULL); } static int sf_setbuff(pcap_t *p, int dim) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The kernel buffer size cannot be set while reading from a file"); return (-1); } static int sf_setmode(pcap_t *p, int mode) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "impossible to set mode while reading from a file"); return (-1); } static int sf_setmintocopy(pcap_t *p, int size) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The mintocopy parameter cannot be set while reading from a file"); return (-1); } static HANDLE sf_getevent(pcap_t *pcap) { (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), "The read event cannot be retrieved while reading from a file"); return (INVALID_HANDLE_VALUE); } static int sf_oid_get_request(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, size_t *lenp _U_) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "An OID get request cannot be performed on a file"); return (PCAP_ERROR); } static int sf_oid_set_request(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_, size_t *lenp _U_) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "An OID set request cannot be performed on a file"); return (PCAP_ERROR); } static u_int sf_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync) { strlcpy(p->errbuf, "Sending packets isn't supported on savefiles", PCAP_ERRBUF_SIZE); return (0); } static int sf_setuserbuffer(pcap_t *p, int size) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The user buffer cannot be set when reading from a file"); return (-1); } static int sf_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Live packet dumping cannot be performed when reading from a file"); return (-1); } static int sf_live_dump_ended(pcap_t *p, int sync) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Live packet dumping cannot be performed on a pcap_open_dead pcap_t"); return (-1); } static PAirpcapHandle sf_get_airpcap_handle(pcap_t *pcap) { return (NULL); } #endif static int sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) { strlcpy(p->errbuf, "Sending packets isn't supported on savefiles", PCAP_ERRBUF_SIZE); return (-1); } /* * Set direction flag: Which packets do we accept on a forwarding * single device? IN, OUT or both? */ static int sf_setdirection(pcap_t *p, pcap_direction_t d) { pcap_snprintf(p->errbuf, sizeof(p->errbuf), "Setting direction is not supported on savefiles"); return (-1); } void sf_cleanup(pcap_t *p) { if (p->rfile != stdin) (void)fclose(p->rfile); if (p->buffer != NULL) free(p->buffer); pcap_freecode(&p->fcode); } /* * fopen's safe version on Windows. */ #ifdef _MSC_VER FILE *fopen_safe(const char *filename, const char* mode) { FILE *fp = NULL; errno_t errno; errno = fopen_s(&fp, filename, mode); if (errno == 0) return fp; else return NULL; } #endif pcap_t * pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision, char *errbuf) { FILE *fp; pcap_t *p; if (fname == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "A null pointer was supplied as the file name"); return (NULL); } if (fname[0] == '-' && fname[1] == '\0') { fp = stdin; #if defined(_WIN32) || defined(MSDOS) /* * We're reading from the standard input, so put it in binary * mode, as savefiles are binary files. */ SET_BINMODE(fp); #endif } else { #if !defined(_WIN32) && !defined(MSDOS) fp = fopen(fname, "r"); #else fp = fopen(fname, "rb"); #endif if (fp == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, pcap_strerror(errno)); return (NULL); } } p = pcap_fopen_offline_with_tstamp_precision(fp, precision, errbuf); if (p == NULL) { if (fp != stdin) fclose(fp); } return (p); } pcap_t * pcap_open_offline(const char *fname, char *errbuf) { return (pcap_open_offline_with_tstamp_precision(fname, PCAP_TSTAMP_PRECISION_MICRO, errbuf)); } #ifdef _WIN32 pcap_t* pcap_hopen_offline_with_tstamp_precision(intptr_t osfd, u_int precision, char *errbuf) { int fd; FILE *file; fd = _open_osfhandle(osfd, _O_RDONLY); if ( fd < 0 ) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno)); return NULL; } file = _fdopen(fd, "rb"); if ( file == NULL ) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno)); return NULL; } return pcap_fopen_offline_with_tstamp_precision(file, precision, errbuf); } pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf) { return pcap_hopen_offline_with_tstamp_precision(osfd, PCAP_TSTAMP_PRECISION_MICRO, errbuf); } #endif static pcap_t *(*check_headers[])(bpf_u_int32, FILE *, u_int, char *, int *) = { pcap_check_header, pcap_ng_check_header }; #define N_FILE_TYPES (sizeof check_headers / sizeof check_headers[0]) #ifdef _WIN32 static #endif pcap_t * pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision, char *errbuf) { register pcap_t *p; bpf_u_int32 magic; size_t amt_read; u_int i; int err; /* * Read the first 4 bytes of the file; the network analyzer dump * file formats we support (pcap and pcap-ng), and several other * formats we might support in the future (such as snoop, DOS and * Windows Sniffer, and Microsoft Network Monitor) all have magic * numbers that are unique in their first 4 bytes. */ amt_read = fread((char *)&magic, 1, sizeof(magic), fp); if (amt_read != sizeof(magic)) { if (ferror(fp)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %lu file header bytes, only got %lu", (unsigned long)sizeof(magic), (unsigned long)amt_read); } return (NULL); } /* * Try all file types. */ for (i = 0; i < N_FILE_TYPES; i++) { p = (*check_headers[i])(magic, fp, precision, errbuf, &err); if (p != NULL) { /* Yup, that's it. */ goto found; } if (err) { /* * Error trying to read the header. */ return (NULL); } } /* * Well, who knows what this mess is.... */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format"); return (NULL); found: p->rfile = fp; /* Padding only needed for live capture fcode */ p->fddipad = 0; #if !defined(_WIN32) && !defined(MSDOS) /* * You can do "select()" and "poll()" on plain files on most * platforms, and should be able to do so on pipes. * * You can't do "select()" on anything other than sockets in * Windows, so, on Win32 systems, we don't have "selectable_fd". */ p->selectable_fd = fileno(fp); #endif p->read_op = pcap_offline_read; p->inject_op = sf_inject; p->setfilter_op = install_bpf_program; p->setdirection_op = sf_setdirection; p->set_datalink_op = NULL; /* we don't support munging link-layer headers */ p->getnonblock_op = sf_getnonblock; p->setnonblock_op = sf_setnonblock; p->stats_op = sf_stats; #ifdef _WIN32 p->stats_ex_op = sf_stats_ex; p->setbuff_op = sf_setbuff; p->setmode_op = sf_setmode; p->setmintocopy_op = sf_setmintocopy; p->getevent_op = sf_getevent; p->oid_get_request_op = sf_oid_get_request; p->oid_set_request_op = sf_oid_set_request; p->sendqueue_transmit_op = sf_sendqueue_transmit; p->setuserbuffer_op = sf_setuserbuffer; p->live_dump_op = sf_live_dump; p->live_dump_ended_op = sf_live_dump_ended; p->get_airpcap_handle_op = sf_get_airpcap_handle; #endif /* * For offline captures, the standard one-shot callback can * be used for pcap_next()/pcap_next_ex(). */ p->oneshot_callback = pcap_oneshot; /* * Savefiles never require special BPF code generation. */ p->bpf_codegen_flags = 0; p->activated = 1; return (p); } #ifdef _WIN32 static #endif pcap_t * pcap_fopen_offline(FILE *fp, char *errbuf) { return (pcap_fopen_offline_with_tstamp_precision(fp, PCAP_TSTAMP_PRECISION_MICRO, errbuf)); } /* * Read packets from a capture file, and call the callback for each * packet. * If cnt > 0, return after 'cnt' packets, otherwise continue until eof. */ int pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct bpf_insn *fcode; int status = 0; int n = 0; u_char *data; while (status == 0) { struct pcap_pkthdr h; /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return -2 to indicate * that we were told to break out of the loop, otherwise * leave the flag set, so that the *next* call will break * out of the loop without having read any packets, and * return the number of packets we've processed so far. */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return (-2); } else return (n); } status = p->next_packet_op(p, &h, &data); if (status) { if (status == 1) return (0); return (status); } if ((fcode = p->fcode.bf_insns) == NULL || bpf_filter(fcode, data, h.len, h.caplen)) { (*callback)(user, &h, data); if (++n >= cnt && cnt > 0) break; } } /*XXX this breaks semantics tcpslice expects */ return (n); } libpcap-1.8.1/pcap-tstamp.manmisc.in0000644000026300017510000001773113003771737015506 0ustar mcrmcr.\" .\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" 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. .\" .TH PCAP-TSTAMP @MAN_MISC_INFO@ "8 March 2015" .SH NAME pcap-tstamp \- packet time stamps in libpcap .SH DESCRIPTION When capturing traffic, each packet is given a time stamp representing, for incoming packets, the arrival time of the packet and, for outgoing packets, the transmission time of the packet. This time is an approximation of the arrival or transmission time. If it is supplied by the operating system running on the host on which the capture is being done, there are several reasons why it might not precisely represent the arrival or transmission time: .IP if the time stamp is applied to the packet when the networking stack receives the packet, the networking stack might not see the packet until an interrupt is delivered for the packet or a timer event causes the networking device driver to poll for packets, and the time stamp might not be applied until the packet has had some processing done by other code in the networking stack, so there might be a significant delay between the time when the last bit of the packet is received by the capture device and when the networking stack time-stamps the packet; .IP the timer used to generate the time stamps might have low resolution, for example, it might be a timer updated once per host operating system timer tick, with the host operating system timer ticking once every few milliseconds; .IP a high-resolution timer might use a counter that runs at a rate dependent on the processor clock speed, and that clock speed might be adjusted upwards or downwards over time and the timer might not be able to compensate for all those adjustments; .IP the host operating system's clock might be adjusted over time to match a time standard to which the host is being synchronized, which might be done by temporarily slowing down or speeding up the clock or by making a single adjustment; .IP different CPU cores on a multi-core or multi-processor system might be running at different speeds, or might not have time counters all synchronized, so packets time-stamped by different cores might not have consistent time stamps. .LP In addition, packets time-stamped by different cores might be time-stamped in one order and added to the queue of packets for libpcap to read in another order, so time stamps might not be monotonically increasing. .LP Some capture devices on some platforms can provide time stamps for packets; those time stamps are usually high-resolution time stamps, and are usually applied to the packet when the first or last bit of the packet arrives, and are thus more accurate than time stamps provided by the host operating system. Those time stamps might not, however, be synchronized with the host operating system's clock, so that, for example, the time stamp of a packet might not correspond to the time stamp of an event on the host triggered by the arrival of that packet. .LP Depending on the capture device and the software on the host, libpcap might allow different types of time stamp to be used. The .BR pcap_list_tstamp_types (3PCAP) routine provides, for a packet capture handle created by .BR pcap_create (3PCAP) but not yet activated by .BR pcap_activate (3PCAP), a list of time stamp types supported by the capture device for that handle. The list might be empty, in which case no choice of time stamp type is offered for that capture device. If the list is not empty, the .BR pcap_set_tstamp_type (3PCAP) routine can be used after a .B pcap_create() call and before a .B pcap_activate() call to specify the type of time stamp to be used on the device. The time stamp types are listed here; the first value is the #define to use in code, the second value is the value returned by .B pcap_tstamp_type_val_to_name() and accepted by .BR pcap_tstamp_type_name_to_val() . .RS 5 .TP 5 .BR PCAP_TSTAMP_HOST " - " host Time stamp provided by the host on which the capture is being done. The precision of this time stamp is unspecified; it might or might not be synchronized with the host operating system's clock. .TP 5 .BR PCAP_TSTAMP_HOST_LOWPREC " - " host_lowprec Time stamp provided by the host on which the capture is being done. This is a low-precision time stamp, synchronized with the host operating system's clock. .TP 5 .BR PCAP_TSTAMP_HOST_HIPREC " - " host_hiprec Time stamp provided by the host on which the capture is being done. This is a high-precision time stamp; it might or might not be synchronized with the host operating system's clock. It might be more expensive to fetch than .BR PCAP_TSTAMP_HOST_LOWPREC . .TP 5 .BR PCAP_TSTAMP_ADAPTER " - " adapter Time stamp provided by the network adapter on which the capture is being done. This is a high-precision time stamp, synchronized with the host operating system's clock. .TP 5 .BR PCAP_TSTAMP_ADAPTER_UNSYNCED " - " adapter_unsynced Time stamp provided by the network adapter on which the capture is being done. This is a high-precision time stamp; it is not synchronized with the host operating system's clock. .RE .LP By default, when performing a live capture or reading from a savefile, time stamps are supplied as seconds since January 1, 1970, 00:00:00 UTC, and microseconds since that seconds value, even if higher-resolution time stamps are available from the capture device or in the savefile. If, when reading a savefile, the time stamps in the file have a higher resolution than one microsecond, the additional digits of resolution are discarded. .LP The .BR pcap_set_tstamp_precision (3PCAP) routine can be used after a .B pcap_create() call and after a .B pcap_activate() call to specify the resolution of the time stamps to get for the device. If the hardware or software cannot supply a higher-resolution time stamp, the .B pcap_set_tstamp_precision() call will fail, and the time stamps supplied after the .B pcap_activate() call will have microsecond resolution. .LP When opening a savefile, the .BR pcap_open_offline_with_tstamp_precision (3PCAP) and .BR pcap_fopen_offline_with_tstamp_precision (3PCAP) routines can be used to specify the resolution of time stamps to be read from the file; if the time stamps in the file have a lower resolution, the fraction-of-a-second portion of the time stamps will be scaled to the specified resolution. .LP The .BR pcap_get_tstamp_precision (3PCAP) routine returns the resolution of time stamps that will be supplied; when capturing packets, this does not reflect the actual precision of the time stamp supplied by the hardware or operating system and, when reading a savefile, this does not indicate the actual precision of time stamps in the file. .SH SEE ALSO pcap_set_tstamp_type(3PCAP), pcap_list_tstamp_types(3PCAP), pcap_tstamp_type_val_to_name(3PCAP), pcap_tstamp_type_name_to_val(3PCAP), pcap_set_tstamp_precision(3PCAP), pcap_open_offline_with_tstamp_precision(3PCAP), pcap_fopen_offline_with_tstamp_precision(3PCAP), pcap_get_tstamp_precision(3PCAP) libpcap-1.8.1/README.hpux0000644000026300017510000002005213003771737013130 0ustar mcrmcrFor HP-UX 11i (11.11) and later, there are no known issues with promiscuous mode under HP-UX. If you are using a earlier version of HP-UX and cannot upgrade, please continue reading. HP-UX patches to fix packet capture problems Note that packet-capture programs such as tcpdump may, on HP-UX, not be able to see packets sent from the machine on which they're running. Some articles on groups.google.com discussing this are: http://groups.google.com/groups?selm=82ld3v%2480i%241%40mamenchi.zrz.TU-Berlin.DE which says: Newsgroups: comp.sys.hp.hpux Subject: Re: Did someone made tcpdump working on 10.20 ? Date: 12/08/1999 From: Lutz Jaenicke In article <82ks5i$5vc$1@news1.dti.ne.jp>, mtsat wrote: >Hello, > >I downloaded and compiled tcpdump3.4 a couple of week ago. I tried to use >it, but I can only see incoming data, never outgoing. >Someone (raj) explained me that a patch was missing, and that this patch >must me "patched" (poked) in order to see outbound data in promiscuous mode. >Many things to do .... So the question is : did someone has already this >"ready to use" PHNE_**** patch ? Two things: 1. You do need a late "LAN products cumulative patch" (e.g. PHNE_18173 for s700/10.20). 2. You must use echo 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem You can insert this e.g. into /sbin/init.d/lan Best regards, Lutz and http://groups.google.com/groups?selm=88cf4t%24p03%241%40web1.cup.hp.com which says: Newsgroups: comp.sys.hp.hpux Subject: Re: tcpdump only shows incoming packets Date: 02/15/2000 From: Rick Jones Harald Skotnes wrote: > I am running HPUX 11.0 on a C200 hanging on a 100Mb switch. I have > compiled libpcap-0.4 an tcpdump-3.4 and it seems to work. But at a > closer look I only get to see the incoming packets not the > outgoing. I have tried tcpflow-0.12 which also uses libpcap and the > same thing happens. Could someone please give me a hint on how to > get this right? Search/Read the archives ?-) What you are seeing is expected, un-patched, behaviour for an HP-UX system. On 11.00, you need to install the latest lancommon/DLPI patches, and then the latest driver patch for the interface(s) in use. At that point, a miracle happens and you should start seeing outbound traffic. [That article also mentions the patch that appears below.] and http://groups.google.com/groups?selm=38AA973E.96BE7DF7%40cc.uit.no which says: Newsgroups: comp.sys.hp.hpux Subject: Re: tcpdump only shows incoming packets Date: 02/16/2000 From: Harald Skotnes Rick Jones wrote: ... > What you are seeing is expected, un-patched, behaviour for an HP-UX > system. On 11.00, you need to install the latest lancommon/DLPI > patches, and then the latest driver patch for the interface(s) in > use. At that point, a miracle happens and you should start seeing > outbound traffic. Thanks a lot. I have this problem on several machines running HPUX 10.20 and 11.00. The machines where patched up before y2k so did not know what to think. Anyway I have now installed PHNE_19766, PHNE_19826, PHNE_20008, PHNE_20735 on the C200 and now I can see the outbound traffic too. Thanks again. (although those patches may not be the ones to install - there may be later patches). And another message to tcpdump-workers@tcpdump.org, from Rick Jones: Date: Mon, 29 Apr 2002 15:59:55 -0700 From: Rick Jones To: tcpdump-workers@tcpdump.org Subject: Re: [tcpdump-workers] I Can't Capture the Outbound Traffic ... http://itrc.hp.com/ would be one place to start in a search for the most up-to-date patches for DLPI and the lan driver(s) used on your system (I cannot guess because 9000/800 is too generic - one hs to use the "model" command these days and/or an ioscan command (see manpage) to guess what the drivers (btlan[3456], gelan, etc) might be involved in addition to DLPI. Another option is to upgrade to 11i as outbound promiscuous mode support is there in the base OS, no patches required. Another posting: http://groups.google.com/groups?selm=7d6gvn%24b3%241%40ocean.cup.hp.com indicates that you need to install the optional STREAMS product to do captures on HP-UX 9.x: Newsgroups: comp.sys.hp.hpux Subject: Re: tcpdump HP/UX 9.x Date: 03/22/1999 From: Rick Jones Dave Barr (barr@cis.ohio-state.edu) wrote: : Has anyone ported tcpdump (or something similar) to HP/UX 9.x? I'm reasonably confident that any port of tcpdump to 9.X would require the (then optional) STREAMS product. This would bring DLPI, which is what one uses to access interfaces in promiscuous mode. I'm not sure that HP even sells the 9.X STREAMS product any longer, since HP-UX 9.X is off the pricelist (well, maybe 9.10 for the old 68K devices). Your best bet is to be up on 10.20 or better if that is at all possible. If your hardware is supported by it, I'd go with HP-UX 11. If you want to see the system's own outbound traffic, you'll never get that functionality on 9.X, but it might happen at some point for 10.20 and 11.X. rick jones (as per other messages cited here, the ability to see the system's own outbound traffic did happen). Rick Jones reports that HP-UX 11i needs no patches for outbound promiscuous mode support. An additional note, from Jost Martin, for HP-UX 10.20: Q: How do I get ethereral on HPUX to capture the _outgoing_ packets of an interface A: You need to get PHNE_20892,PHNE_20725 and PHCO_10947 (or newer, this is as of 4.4.00) and its dependencies. Then you can enable the feature as descibed below: Patch Name: PHNE_20892 Patch Description: s700 10.20 PCI 100Base-T cumulative patch To trace the outbound packets, please do the following to turn on a global promiscuous switch before running the promiscuous applications like snoop or tcpdump: adb -w /stand/vmunix /dev/mem lanc_outbound_promisc_flag/W 1 (adb will echo the result showing that the flag has been changed) $quit (Thanks for this part to HP-support, Ratingen) The attached hack does this and some security-related stuff (thanks to hildeb@www.stahl.bau.tu-bs.de (Ralf Hildebrandt) who posted the security-part some time ago) <> (Don't switch IP-forwarding off, if you need it !) Install the hack as /sbin/init.d/hacl_ip_stack (adjust permissions !) and make a sequencing-symlink /sbin/rc2.d/S350hack_ip_stack pointing to this script. Now all this is done on every reboot. According to Rick Jones, the global promiscuous switch also has to be turned on for HP-UX 11.00, but not for 11i - and, in fact, the switch doesn't even exist on 11i. Here's the "hack_ip_stack" script: -----------------------------------Cut Here------------------------------------- #!/sbin/sh # # nettune: hack kernel parms for safety OKAY=0 ERROR=-1 # /usr/contrib/bin fuer nettune auf Pfad PATH=/sbin:/usr/sbin:/usr/bin:/usr/contrib/bin export PATH ########## # main # ########## case $1 in start_msg) print "Tune IP-Stack for security" exit $OKAY ;; stop_msg) print "This action is not applicable" exit $OKAY ;; stop) exit $OKAY ;; start) ;; # fall through *) print "USAGE: $0 {start_msg | stop_msg | start | stop}" >&2 exit $ERROR ;; esac ########### # start # ########### # # tcp-Sequence-Numbers nicht mehr inkrementieren sondern random # Syn-Flood-Protection an # ip_forwarding aus # Source-Routing aus # Ausgehende Packets an ethereal/tcpdump etc. /usr/contrib/bin/nettune -s tcp_random_seq 2 || exit $ERROR /usr/contrib/bin/nettune -s hp_syn_protect 1 || exit $ERROR /usr/contrib/bin/nettune -s ip_forwarding 0 || exit $ERROR echo 'ip_block_source_routed/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem || exit $ERROR echo 'lanc_outbound_promisc_flag/W 1' | adb -w /stand/vmunix /dev/mem || exit $ERROR exit $OKAY -----------------------------------Cut Here------------------------------------- libpcap-1.8.1/pcap-linux.c0000644000026300017510000057237613003771737013536 0ustar mcrmcr/* * pcap-linux.c: Packet capture interface to the Linux kernel * * Copyright (c) 2000 Torsten Landschoff * Sebastian Krahmer * * License: BSD * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. The names of the authors may not 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. * * Modifications: Added PACKET_MMAP support * Paolo Abeni * Added TPACKET_V3 support * Gabor Tatarka * * based on previous works of: * Simon Patarin * Phil Wood * * Monitor-mode support for mac80211 includes code taken from the iw * command; the copyright notice for that code is * * Copyright (c) 2007, 2008 Johannes Berg * Copyright (c) 2007 Andy Lutomirski * Copyright (c) 2007 Mike Kershaw * Copyright (c) 2008 Gábor Stefanik * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Known problems with 2.0[.x] kernels: * * - The loopback device gives every packet twice; on 2.2[.x] kernels, * if we use PF_PACKET, we can filter out the transmitted version * of the packet by using data in the "sockaddr_ll" returned by * "recvfrom()", but, on 2.0[.x] kernels, we have to use * PF_INET/SOCK_PACKET, which means "recvfrom()" supplies a * "sockaddr_pkt" which doesn't give us enough information to let * us do that. * * - We have to set the interface's IFF_PROMISC flag ourselves, if * we're to run in promiscuous mode, which means we have to turn * it off ourselves when we're done; the kernel doesn't keep track * of how many sockets are listening promiscuously, which means * it won't get turned off automatically when no sockets are * listening promiscuously. We catch "pcap_close()" and, for * interfaces we put into promiscuous mode, take them out of * promiscuous mode - which isn't necessarily the right thing to * do, if another socket also requested promiscuous mode between * the time when we opened the socket and the time when we close * the socket. * * - MSG_TRUNC isn't supported, so you can't specify that "recvfrom()" * return the amount of data that you could have read, rather than * the amount that was returned, so we can't just allocate a buffer * whose size is the snapshot length and pass the snapshot length * as the byte count, and also pass MSG_TRUNC, so that the return * value tells us how long the packet was on the wire. * * This means that, if we want to get the actual size of the packet, * so we can return it in the "len" field of the packet header, * we have to read the entire packet, not just the part that fits * within the snapshot length, and thus waste CPU time copying data * from the kernel that our caller won't see. * * We have to get the actual size, and supply it in "len", because * otherwise, the IP dissector in tcpdump, for example, will complain * about "truncated-ip", as the packet will appear to have been * shorter, on the wire, than the IP header said it should have been. */ #define _GNU_SOURCE #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcap-int.h" #include "pcap/sll.h" #include "pcap/vlan.h" /* * If PF_PACKET is defined, we can use {SOCK_RAW,SOCK_DGRAM}/PF_PACKET * sockets rather than SOCK_PACKET sockets. * * To use them, we include rather than * ; we do so because * * some Linux distributions (e.g., Slackware 4.0) have 2.2 or * later kernels and libc5, and don't provide a * file; * * not all versions of glibc2 have a file * that defines stuff needed for some of the 2.4-or-later-kernel * features, so if the system has a 2.4 or later kernel, we * still can't use those features. * * We're already including a number of other headers, and * this code is Linux-specific (no other OS has PF_PACKET sockets as * a raw packet capture mechanism), so it's not as if you gain any * useful portability by using * * XXX - should we just include even if PF_PACKET * isn't defined? It only defines one data structure in 2.0.x, so * it shouldn't cause any problems. */ #ifdef PF_PACKET # include /* * On at least some Linux distributions (for example, Red Hat 5.2), * there's no file, but PF_PACKET is defined if * you include , but doesn't define * any of the PF_PACKET stuff such as "struct sockaddr_ll" or any of * the PACKET_xxx stuff. * * So we check whether PACKET_HOST is defined, and assume that we have * PF_PACKET sockets only if it is defined. */ # ifdef PACKET_HOST # define HAVE_PF_PACKET_SOCKETS # ifdef PACKET_AUXDATA # define HAVE_PACKET_AUXDATA # endif /* PACKET_AUXDATA */ # endif /* PACKET_HOST */ /* check for memory mapped access avaibility. We assume every needed * struct is defined if the macro TPACKET_HDRLEN is defined, because it * uses many ring related structs and macros */ # ifdef PCAP_SUPPORT_PACKET_RING # ifdef TPACKET_HDRLEN # define HAVE_PACKET_RING # ifdef TPACKET3_HDRLEN # define HAVE_TPACKET3 # endif /* TPACKET3_HDRLEN */ # ifdef TPACKET2_HDRLEN # define HAVE_TPACKET2 # else /* TPACKET2_HDRLEN */ # define TPACKET_V1 0 /* Old kernel with only V1, so no TPACKET_Vn defined */ # endif /* TPACKET2_HDRLEN */ # endif /* TPACKET_HDRLEN */ # endif /* PCAP_SUPPORT_PACKET_RING */ #endif /* PF_PACKET */ #ifdef SO_ATTACH_FILTER #include #include #endif #ifdef HAVE_LINUX_NET_TSTAMP_H #include #endif #ifdef HAVE_LINUX_SOCKIOS_H #include #endif #ifdef HAVE_LINUX_IF_BONDING_H #include /* * The ioctl code to use to check whether a device is a bonding device. */ #if defined(SIOCBONDINFOQUERY) #define BOND_INFO_QUERY_IOCTL SIOCBONDINFOQUERY #elif defined(BOND_INFO_QUERY_OLD) #define BOND_INFO_QUERY_IOCTL BOND_INFO_QUERY_OLD #endif #endif /* HAVE_LINUX_IF_BONDING_H */ /* * Got Wireless Extensions? */ #ifdef HAVE_LINUX_WIRELESS_H #include #endif /* HAVE_LINUX_WIRELESS_H */ /* * Got libnl? */ #ifdef HAVE_LIBNL #include #include #include #include #include #include #endif /* HAVE_LIBNL */ /* * Got ethtool support? */ #ifdef HAVE_LINUX_ETHTOOL_H #include #endif #ifndef HAVE_SOCKLEN_T typedef int socklen_t; #endif #ifndef MSG_TRUNC /* * This is being compiled on a system that lacks MSG_TRUNC; define it * with the value it has in the 2.2 and later kernels, so that, on * those kernels, when we pass it in the flags argument to "recvfrom()" * we're passing the right value and thus get the MSG_TRUNC behavior * we want. (We don't get that behavior on 2.0[.x] kernels, because * they didn't support MSG_TRUNC.) */ #define MSG_TRUNC 0x20 #endif #ifndef SOL_PACKET /* * This is being compiled on a system that lacks SOL_PACKET; define it * with the value it has in the 2.2 and later kernels, so that we can * set promiscuous mode in the good modern way rather than the old * 2.0-kernel crappy way. */ #define SOL_PACKET 263 #endif #define MAX_LINKHEADER_SIZE 256 /* * When capturing on all interfaces we use this as the buffer size. * Should be bigger then all MTUs that occur in real life. * 64kB should be enough for now. */ #define BIGGER_THAN_ALL_MTUS (64*1024) /* * Private data for capturing on Linux SOCK_PACKET or PF_PACKET sockets. */ struct pcap_linux { u_int packets_read; /* count of packets read with recvfrom() */ long proc_dropped; /* packets reported dropped by /proc/net/dev */ struct pcap_stat stat; char *device; /* device name */ int filter_in_userland; /* must filter in userland */ int blocks_to_filter_in_userland; int must_do_on_close; /* stuff we must do when we close */ int timeout; /* timeout for buffering */ int sock_packet; /* using Linux 2.0 compatible interface */ int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */ int ifindex; /* interface index of device we're bound to */ int lo_ifindex; /* interface index of the loopback device */ bpf_u_int32 oldmode; /* mode to restore when turning monitor mode off */ char *mondevice; /* mac80211 monitor device we created */ u_char *mmapbuf; /* memory-mapped region pointer */ size_t mmapbuflen; /* size of region */ int vlan_offset; /* offset at which to insert vlan tags; if -1, don't insert */ u_int tp_version; /* version of tpacket_hdr for mmaped ring */ u_int tp_hdrlen; /* hdrlen of tpacket_hdr for mmaped ring */ u_char *oneshot_buffer; /* buffer for copy of packet */ int poll_timeout; /* timeout to use in poll() */ #ifdef HAVE_TPACKET3 unsigned char *current_packet; /* Current packet within the TPACKET_V3 block. Move to next block if NULL. */ int packets_left; /* Unhandled packets left within the block from previous call to pcap_read_linux_mmap_v3 in case of TPACKET_V3. */ #endif }; /* * Stuff to do when we close. */ #define MUST_CLEAR_PROMISC 0x00000001 /* clear promiscuous mode */ #define MUST_CLEAR_RFMON 0x00000002 /* clear rfmon (monitor) mode */ #define MUST_DELETE_MONIF 0x00000004 /* delete monitor-mode interface */ /* * Prototypes for internal functions and methods. */ static void map_arphrd_to_dlt(pcap_t *, int, int, const char *, int); #ifdef HAVE_PF_PACKET_SOCKETS static short int map_packet_type_to_sll_type(short int); #endif static int pcap_activate_linux(pcap_t *); static int activate_old(pcap_t *); static int activate_new(pcap_t *); static int activate_mmap(pcap_t *, int *); static int pcap_can_set_rfmon_linux(pcap_t *); static int pcap_read_linux(pcap_t *, int, pcap_handler, u_char *); static int pcap_read_packet(pcap_t *, pcap_handler, u_char *); static int pcap_inject_linux(pcap_t *, const void *, size_t); static int pcap_stats_linux(pcap_t *, struct pcap_stat *); static int pcap_setfilter_linux(pcap_t *, struct bpf_program *); static int pcap_setdirection_linux(pcap_t *, pcap_direction_t); static int pcap_set_datalink_linux(pcap_t *, int); static void pcap_cleanup_linux(pcap_t *); /* * This is what the header structure looks like in a 64-bit kernel; * we use this, rather than struct tpacket_hdr, if we're using * TPACKET_V1 in 32-bit code running on a 64-bit kernel. */ struct tpacket_hdr_64 { uint64_t tp_status; unsigned int tp_len; unsigned int tp_snaplen; unsigned short tp_mac; unsigned short tp_net; unsigned int tp_sec; unsigned int tp_usec; }; /* * We use this internally as the tpacket version for TPACKET_V1 in * 32-bit code on a 64-bit kernel. */ #define TPACKET_V1_64 99 union thdr { struct tpacket_hdr *h1; struct tpacket_hdr_64 *h1_64; #ifdef HAVE_TPACKET2 struct tpacket2_hdr *h2; #endif #ifdef HAVE_TPACKET3 struct tpacket_block_desc *h3; #endif void *raw; }; #ifdef HAVE_PACKET_RING #define RING_GET_FRAME_AT(h, offset) (((union thdr **)h->buffer)[(offset)]) #define RING_GET_CURRENT_FRAME(h) RING_GET_FRAME_AT(h, h->offset) static void destroy_ring(pcap_t *handle); static int create_ring(pcap_t *handle, int *status); static int prepare_tpacket_socket(pcap_t *handle); static void pcap_cleanup_linux_mmap(pcap_t *); static int pcap_read_linux_mmap_v1(pcap_t *, int, pcap_handler , u_char *); static int pcap_read_linux_mmap_v1_64(pcap_t *, int, pcap_handler , u_char *); #ifdef HAVE_TPACKET2 static int pcap_read_linux_mmap_v2(pcap_t *, int, pcap_handler , u_char *); #endif #ifdef HAVE_TPACKET3 static int pcap_read_linux_mmap_v3(pcap_t *, int, pcap_handler , u_char *); #endif static int pcap_setfilter_linux_mmap(pcap_t *, struct bpf_program *); static int pcap_setnonblock_mmap(pcap_t *p, int nonblock, char *errbuf); static int pcap_getnonblock_mmap(pcap_t *p, char *errbuf); static void pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes); #endif #ifdef TP_STATUS_VLAN_TPID_VALID # define VLAN_TPID(hdr, hv) (((hv)->tp_vlan_tpid || ((hdr)->tp_status & TP_STATUS_VLAN_TPID_VALID)) ? (hv)->tp_vlan_tpid : ETH_P_8021Q) #else # define VLAN_TPID(hdr, hv) ETH_P_8021Q #endif /* * Wrap some ioctl calls */ #ifdef HAVE_PF_PACKET_SOCKETS static int iface_get_id(int fd, const char *device, char *ebuf); #endif /* HAVE_PF_PACKET_SOCKETS */ static int iface_get_mtu(int fd, const char *device, char *ebuf); static int iface_get_arptype(int fd, const char *device, char *ebuf); #ifdef HAVE_PF_PACKET_SOCKETS static int iface_bind(int fd, int ifindex, char *ebuf); #ifdef IW_MODE_MONITOR static int has_wext(int sock_fd, const char *device, char *ebuf); #endif /* IW_MODE_MONITOR */ static int enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device); #endif /* HAVE_PF_PACKET_SOCKETS */ #if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) static int iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf); #endif #ifdef HAVE_PACKET_RING static int iface_get_offload(pcap_t *handle); #endif static int iface_bind_old(int fd, const char *device, char *ebuf); #ifdef SO_ATTACH_FILTER static int fix_program(pcap_t *handle, struct sock_fprog *fcode, int is_mapped); static int fix_offset(struct bpf_insn *p); static int set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode); static int reset_kernel_filter(pcap_t *handle); static struct sock_filter total_insn = BPF_STMT(BPF_RET | BPF_K, 0); static struct sock_fprog total_fcode = { 1, &total_insn }; #endif /* SO_ATTACH_FILTER */ pcap_t * pcap_create_interface(const char *device, char *ebuf) { pcap_t *handle; handle = pcap_create_common(ebuf, sizeof (struct pcap_linux)); if (handle == NULL) return NULL; handle->activate_op = pcap_activate_linux; handle->can_set_rfmon_op = pcap_can_set_rfmon_linux; #if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) /* * See what time stamp types we support. */ if (iface_ethtool_get_ts_info(device, handle, ebuf) == -1) { pcap_close(handle); return NULL; } #endif #if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) /* * We claim that we support microsecond and nanosecond time * stamps. * * XXX - with adapter-supplied time stamps, can we choose * microsecond or nanosecond time stamps on arbitrary * adapters? */ handle->tstamp_precision_count = 2; handle->tstamp_precision_list = malloc(2 * sizeof(u_int)); if (handle->tstamp_precision_list == NULL) { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); pcap_close(handle); return NULL; } handle->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; handle->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; #endif /* defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) */ return handle; } #ifdef HAVE_LIBNL /* * If interface {if} is a mac80211 driver, the file * /sys/class/net/{if}/phy80211 is a symlink to * /sys/class/ieee80211/{phydev}, for some {phydev}. * * On Fedora 9, with a 2.6.26.3-29 kernel, my Zydas stick, at * least, has a "wmaster0" device and a "wlan0" device; the * latter is the one with the IP address. Both show up in * "tcpdump -D" output. Capturing on the wmaster0 device * captures with 802.11 headers. * * airmon-ng searches through /sys/class/net for devices named * monN, starting with mon0; as soon as one *doesn't* exist, * it chooses that as the monitor device name. If the "iw" * command exists, it does "iw dev {if} interface add {monif} * type monitor", where {monif} is the monitor device. It * then (sigh) sleeps .1 second, and then configures the * device up. Otherwise, if /sys/class/ieee80211/{phydev}/add_iface * is a file, it writes {mondev}, without a newline, to that file, * and again (sigh) sleeps .1 second, and then iwconfig's that * device into monitor mode and configures it up. Otherwise, * you can't do monitor mode. * * All these devices are "glued" together by having the * /sys/class/net/{device}/phy80211 links pointing to the same * place, so, given a wmaster, wlan, or mon device, you can * find the other devices by looking for devices with * the same phy80211 link. * * To turn monitor mode off, delete the monitor interface, * either with "iw dev {monif} interface del" or by sending * {monif}, with no NL, down /sys/class/ieee80211/{phydev}/remove_iface * * Note: if you try to create a monitor device named "monN", and * there's already a "monN" device, it fails, as least with * the netlink interface (which is what iw uses), with a return * value of -ENFILE. (Return values are negative errnos.) We * could probably use that to find an unused device. * * Yes, you can have multiple monitor devices for a given * physical device. */ /* * Is this a mac80211 device? If so, fill in the physical device path and * return 1; if not, return 0. On an error, fill in handle->errbuf and * return PCAP_ERROR. */ static int get_mac80211_phydev(pcap_t *handle, const char *device, char *phydev_path, size_t phydev_max_pathlen) { char *pathstr; ssize_t bytes_read; /* * Generate the path string for the symlink to the physical device. */ if (asprintf(&pathstr, "/sys/class/net/%s/phy80211", device) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: Can't generate path name string for /sys/class/net device", device); return PCAP_ERROR; } bytes_read = readlink(pathstr, phydev_path, phydev_max_pathlen); if (bytes_read == -1) { if (errno == ENOENT || errno == EINVAL) { /* * Doesn't exist, or not a symlink; assume that * means it's not a mac80211 device. */ free(pathstr); return 0; } pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: Can't readlink %s: %s", device, pathstr, strerror(errno)); free(pathstr); return PCAP_ERROR; } free(pathstr); phydev_path[bytes_read] = '\0'; return 1; } #ifdef HAVE_LIBNL_SOCKETS #define get_nl_errmsg nl_geterror #else /* libnl 2.x compatibility code */ #define nl_sock nl_handle static inline struct nl_handle * nl_socket_alloc(void) { return nl_handle_alloc(); } static inline void nl_socket_free(struct nl_handle *h) { nl_handle_destroy(h); } #define get_nl_errmsg strerror static inline int __genl_ctrl_alloc_cache(struct nl_handle *h, struct nl_cache **cache) { struct nl_cache *tmp = genl_ctrl_alloc_cache(h); if (!tmp) return -ENOMEM; *cache = tmp; return 0; } #define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache #endif /* !HAVE_LIBNL_SOCKETS */ struct nl80211_state { struct nl_sock *nl_sock; struct nl_cache *nl_cache; struct genl_family *nl80211; }; static int nl80211_init(pcap_t *handle, struct nl80211_state *state, const char *device) { int err; state->nl_sock = nl_socket_alloc(); if (!state->nl_sock) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: failed to allocate netlink handle", device); return PCAP_ERROR; } if (genl_connect(state->nl_sock)) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: failed to connect to generic netlink", device); goto out_handle_destroy; } err = genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache); if (err < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: failed to allocate generic netlink cache: %s", device, get_nl_errmsg(-err)); goto out_handle_destroy; } state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211"); if (!state->nl80211) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl80211 not found", device); goto out_cache_free; } return 0; out_cache_free: nl_cache_free(state->nl_cache); out_handle_destroy: nl_socket_free(state->nl_sock); return PCAP_ERROR; } static void nl80211_cleanup(struct nl80211_state *state) { genl_family_put(state->nl80211); nl_cache_free(state->nl_cache); nl_socket_free(state->nl_sock); } static int del_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state, const char *device, const char *mondevice); static int add_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state, const char *device, const char *mondevice) { struct pcap_linux *handlep = handle->priv; int ifindex; struct nl_msg *msg; int err; ifindex = iface_get_id(sock_fd, device, handle->errbuf); if (ifindex == -1) return PCAP_ERROR; msg = nlmsg_alloc(); if (!msg) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: failed to allocate netlink msg", device); return PCAP_ERROR; } genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0, NL80211_CMD_NEW_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, mondevice); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); err = nl_send_auto_complete(state->nl_sock, msg); if (err < 0) { #if defined HAVE_LIBNL_NLE if (err == -NLE_FAILURE) { #else if (err == -ENFILE) { #endif /* * Device not available; our caller should just * keep trying. (libnl 2.x maps ENFILE to * NLE_FAILURE; it can also map other errors * to that, but there's not much we can do * about that.) */ nlmsg_free(msg); return 0; } else { /* * Real failure, not just "that device is not * available. */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl_send_auto_complete failed adding %s interface: %s", device, mondevice, get_nl_errmsg(-err)); nlmsg_free(msg); return PCAP_ERROR; } } err = nl_wait_for_ack(state->nl_sock); if (err < 0) { #if defined HAVE_LIBNL_NLE if (err == -NLE_FAILURE) { #else if (err == -ENFILE) { #endif /* * Device not available; our caller should just * keep trying. (libnl 2.x maps ENFILE to * NLE_FAILURE; it can also map other errors * to that, but there's not much we can do * about that.) */ nlmsg_free(msg); return 0; } else { /* * Real failure, not just "that device is not * available. */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl_wait_for_ack failed adding %s interface: %s", device, mondevice, get_nl_errmsg(-err)); nlmsg_free(msg); return PCAP_ERROR; } } /* * Success. */ nlmsg_free(msg); /* * Try to remember the monitor device. */ handlep->mondevice = strdup(mondevice); if (handlep->mondevice == NULL) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", pcap_strerror(errno)); /* * Get rid of the monitor device. */ del_mon_if(handle, sock_fd, state, device, mondevice); return PCAP_ERROR; } return 1; nla_put_failure: pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl_put failed adding %s interface", device, mondevice); nlmsg_free(msg); return PCAP_ERROR; } static int del_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state, const char *device, const char *mondevice) { int ifindex; struct nl_msg *msg; int err; ifindex = iface_get_id(sock_fd, mondevice, handle->errbuf); if (ifindex == -1) return PCAP_ERROR; msg = nlmsg_alloc(); if (!msg) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: failed to allocate netlink msg", device); return PCAP_ERROR; } genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0, NL80211_CMD_DEL_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); err = nl_send_auto_complete(state->nl_sock, msg); if (err < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl_send_auto_complete failed deleting %s interface: %s", device, mondevice, get_nl_errmsg(-err)); nlmsg_free(msg); return PCAP_ERROR; } err = nl_wait_for_ack(state->nl_sock); if (err < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl_wait_for_ack failed adding %s interface: %s", device, mondevice, get_nl_errmsg(-err)); nlmsg_free(msg); return PCAP_ERROR; } /* * Success. */ nlmsg_free(msg); return 1; nla_put_failure: pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl_put failed deleting %s interface", device, mondevice); nlmsg_free(msg); return PCAP_ERROR; } static int enter_rfmon_mode_mac80211(pcap_t *handle, int sock_fd, const char *device) { struct pcap_linux *handlep = handle->priv; int ret; char phydev_path[PATH_MAX+1]; struct nl80211_state nlstate; struct ifreq ifr; u_int n; /* * Is this a mac80211 device? */ ret = get_mac80211_phydev(handle, device, phydev_path, PATH_MAX); if (ret < 0) return ret; /* error */ if (ret == 0) return 0; /* no error, but not mac80211 device */ /* * XXX - is this already a monN device? * If so, we're done. * Is that determined by old Wireless Extensions ioctls? */ /* * OK, it's apparently a mac80211 device. * Try to find an unused monN device for it. */ ret = nl80211_init(handle, &nlstate, device); if (ret != 0) return ret; for (n = 0; n < UINT_MAX; n++) { /* * Try mon{n}. */ char mondevice[3+10+1]; /* mon{UINT_MAX}\0 */ pcap_snprintf(mondevice, sizeof mondevice, "mon%u", n); ret = add_mon_if(handle, sock_fd, &nlstate, device, mondevice); if (ret == 1) { /* * Success. We don't clean up the libnl state * yet, as we'll be using it later. */ goto added; } if (ret < 0) { /* * Hard failure. Just return ret; handle->errbuf * has already been set. */ nl80211_cleanup(&nlstate); return ret; } } pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: No free monN interfaces", device); nl80211_cleanup(&nlstate); return PCAP_ERROR; added: #if 0 /* * Sleep for .1 seconds. */ delay.tv_sec = 0; delay.tv_nsec = 500000000; nanosleep(&delay, NULL); #endif /* * If we haven't already done so, arrange to have * "pcap_close_all()" called when we exit. */ if (!pcap_do_addexit(handle)) { /* * "atexit()" failed; don't put the interface * in rfmon mode, just give up. */ del_mon_if(handle, sock_fd, &nlstate, device, handlep->mondevice); nl80211_cleanup(&nlstate); return PCAP_ERROR; } /* * Now configure the monitor interface up. */ memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name)); if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: Can't get flags for %s: %s", device, handlep->mondevice, strerror(errno)); del_mon_if(handle, sock_fd, &nlstate, device, handlep->mondevice); nl80211_cleanup(&nlstate); return PCAP_ERROR; } ifr.ifr_flags |= IFF_UP|IFF_RUNNING; if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: Can't set flags for %s: %s", device, handlep->mondevice, strerror(errno)); del_mon_if(handle, sock_fd, &nlstate, device, handlep->mondevice); nl80211_cleanup(&nlstate); return PCAP_ERROR; } /* * Success. Clean up the libnl state. */ nl80211_cleanup(&nlstate); /* * Note that we have to delete the monitor device when we close * the handle. */ handlep->must_do_on_close |= MUST_DELETE_MONIF; /* * Add this to the list of pcaps to close when we exit. */ pcap_add_to_pcaps_to_close(handle); return 1; } #endif /* HAVE_LIBNL */ #ifdef IW_MODE_MONITOR /* * Bonding devices mishandle unknown ioctls; they fail with ENODEV * rather than ENOTSUP, EOPNOTSUPP, or ENOTTY, so Wireless Extensions * will fail with ENODEV if we try to do them on a bonding device, * making us return a "no such device" indication rather than just * saying "no Wireless Extensions". * * So we check for bonding devices, if we can, before trying those * ioctls, by trying a bonding device information query ioctl to see * whether it succeeds. */ static int is_bonding_device(int fd, const char *device) { #ifdef BOND_INFO_QUERY_IOCTL struct ifreq ifr; ifbond ifb; memset(&ifr, 0, sizeof ifr); strlcpy(ifr.ifr_name, device, sizeof ifr.ifr_name); memset(&ifb, 0, sizeof ifb); ifr.ifr_data = (caddr_t)&ifb; if (ioctl(fd, BOND_INFO_QUERY_IOCTL, &ifr) == 0) return 1; /* success, so it's a bonding device */ #endif /* BOND_INFO_QUERY_IOCTL */ return 0; /* no, it's not a bonding device */ } #endif /* IW_MODE_MONITOR */ static int pcap_can_set_rfmon_linux(pcap_t *handle) { #ifdef HAVE_LIBNL char phydev_path[PATH_MAX+1]; int ret; #endif #ifdef IW_MODE_MONITOR int sock_fd; struct iwreq ireq; #endif if (strcmp(handle->opt.device, "any") == 0) { /* * Monitor mode makes no sense on the "any" device. */ return 0; } #ifdef HAVE_LIBNL /* * Bleah. There doesn't seem to be a way to ask a mac80211 * device, through libnl, whether it supports monitor mode; * we'll just check whether the device appears to be a * mac80211 device and, if so, assume the device supports * monitor mode. * * wmaster devices don't appear to support the Wireless * Extensions, but we can create a mon device for a * wmaster device, so we don't bother checking whether * a mac80211 device supports the Wireless Extensions. */ ret = get_mac80211_phydev(handle, handle->opt.device, phydev_path, PATH_MAX); if (ret < 0) return ret; /* error */ if (ret == 1) return 1; /* mac80211 device */ #endif #ifdef IW_MODE_MONITOR /* * Bleah. There doesn't appear to be an ioctl to use to ask * whether a device supports monitor mode; we'll just do * SIOCGIWMODE and, if it succeeds, assume the device supports * monitor mode. * * Open a socket on which to attempt to get the mode. * (We assume that if we have Wireless Extensions support * we also have PF_PACKET support.) */ sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (sock_fd == -1) { (void)pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); return PCAP_ERROR; } if (is_bonding_device(sock_fd, handle->opt.device)) { /* It's a bonding device, so don't even try. */ close(sock_fd); return 0; } /* * Attempt to get the current mode. */ strlcpy(ireq.ifr_ifrn.ifrn_name, handle->opt.device, sizeof ireq.ifr_ifrn.ifrn_name); if (ioctl(sock_fd, SIOCGIWMODE, &ireq) != -1) { /* * Well, we got the mode; assume we can set it. */ close(sock_fd); return 1; } if (errno == ENODEV) { /* The device doesn't even exist. */ (void)pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIWMODE failed: %s", pcap_strerror(errno)); close(sock_fd); return PCAP_ERROR_NO_SUCH_DEVICE; } close(sock_fd); #endif return 0; } /* * Grabs the number of dropped packets by the interface from /proc/net/dev. * * XXX - what about /sys/class/net/{interface name}/rx_*? There are * individual devices giving, in ASCII, various rx_ and tx_ statistics. * * Or can we get them in binary form from netlink? */ static long int linux_if_drops(const char * if_name) { char buffer[512]; char * bufptr; FILE * file; int field_to_convert = 3, if_name_sz = strlen(if_name); long int dropped_pkts = 0; file = fopen("/proc/net/dev", "r"); if (!file) return 0; while (!dropped_pkts && fgets( buffer, sizeof(buffer), file )) { /* search for 'bytes' -- if its in there, then that means we need to grab the fourth field. otherwise grab the third field. */ if (field_to_convert != 4 && strstr(buffer, "bytes")) { field_to_convert = 4; continue; } /* find iface and make sure it actually matches -- space before the name and : after it */ if ((bufptr = strstr(buffer, if_name)) && (bufptr == buffer || *(bufptr-1) == ' ') && *(bufptr + if_name_sz) == ':') { bufptr = bufptr + if_name_sz + 1; /* grab the nth field from it */ while( --field_to_convert && *bufptr != '\0') { while (*bufptr != '\0' && *(bufptr++) == ' '); while (*bufptr != '\0' && *(bufptr++) != ' '); } /* get rid of any final spaces */ while (*bufptr != '\0' && *bufptr == ' ') bufptr++; if (*bufptr != '\0') dropped_pkts = strtol(bufptr, NULL, 10); break; } } fclose(file); return dropped_pkts; } /* * With older kernels promiscuous mode is kind of interesting because we * have to reset the interface before exiting. The problem can't really * be solved without some daemon taking care of managing usage counts. * If we put the interface into promiscuous mode, we set a flag indicating * that we must take it out of that mode when the interface is closed, * and, when closing the interface, if that flag is set we take it out * of promiscuous mode. * * Even with newer kernels, we have the same issue with rfmon mode. */ static void pcap_cleanup_linux( pcap_t *handle ) { struct pcap_linux *handlep = handle->priv; struct ifreq ifr; #ifdef HAVE_LIBNL struct nl80211_state nlstate; int ret; #endif /* HAVE_LIBNL */ #ifdef IW_MODE_MONITOR int oldflags; struct iwreq ireq; #endif /* IW_MODE_MONITOR */ if (handlep->must_do_on_close != 0) { /* * There's something we have to do when closing this * pcap_t. */ if (handlep->must_do_on_close & MUST_CLEAR_PROMISC) { /* * We put the interface into promiscuous mode; * take it out of promiscuous mode. * * XXX - if somebody else wants it in promiscuous * mode, this code cannot know that, so it'll take * it out of promiscuous mode. That's not fixable * in 2.0[.x] kernels. */ memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, handlep->device, sizeof(ifr.ifr_name)); if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) { fprintf(stderr, "Can't restore interface %s flags (SIOCGIFFLAGS failed: %s).\n" "Please adjust manually.\n" "Hint: This can't happen with Linux >= 2.2.0.\n", handlep->device, strerror(errno)); } else { if (ifr.ifr_flags & IFF_PROMISC) { /* * Promiscuous mode is currently on; * turn it off. */ ifr.ifr_flags &= ~IFF_PROMISC; if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) { fprintf(stderr, "Can't restore interface %s flags (SIOCSIFFLAGS failed: %s).\n" "Please adjust manually.\n" "Hint: This can't happen with Linux >= 2.2.0.\n", handlep->device, strerror(errno)); } } } } #ifdef HAVE_LIBNL if (handlep->must_do_on_close & MUST_DELETE_MONIF) { ret = nl80211_init(handle, &nlstate, handlep->device); if (ret >= 0) { ret = del_mon_if(handle, handle->fd, &nlstate, handlep->device, handlep->mondevice); nl80211_cleanup(&nlstate); } if (ret < 0) { fprintf(stderr, "Can't delete monitor interface %s (%s).\n" "Please delete manually.\n", handlep->mondevice, handle->errbuf); } } #endif /* HAVE_LIBNL */ #ifdef IW_MODE_MONITOR if (handlep->must_do_on_close & MUST_CLEAR_RFMON) { /* * We put the interface into rfmon mode; * take it out of rfmon mode. * * XXX - if somebody else wants it in rfmon * mode, this code cannot know that, so it'll take * it out of rfmon mode. */ /* * First, take the interface down if it's up; * otherwise, we might get EBUSY. * If we get errors, just drive on and print * a warning if we can't restore the mode. */ oldflags = 0; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, handlep->device, sizeof(ifr.ifr_name)); if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) != -1) { if (ifr.ifr_flags & IFF_UP) { oldflags = ifr.ifr_flags; ifr.ifr_flags &= ~IFF_UP; if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) oldflags = 0; /* didn't set, don't restore */ } } /* * Now restore the mode. */ strlcpy(ireq.ifr_ifrn.ifrn_name, handlep->device, sizeof ireq.ifr_ifrn.ifrn_name); ireq.u.mode = handlep->oldmode; if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) { /* * Scientist, you've failed. */ fprintf(stderr, "Can't restore interface %s wireless mode (SIOCSIWMODE failed: %s).\n" "Please adjust manually.\n", handlep->device, strerror(errno)); } /* * Now bring the interface back up if we brought * it down. */ if (oldflags != 0) { ifr.ifr_flags = oldflags; if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) { fprintf(stderr, "Can't bring interface %s back up (SIOCSIFFLAGS failed: %s).\n" "Please adjust manually.\n", handlep->device, strerror(errno)); } } } #endif /* IW_MODE_MONITOR */ /* * Take this pcap out of the list of pcaps for which we * have to take the interface out of some mode. */ pcap_remove_from_pcaps_to_close(handle); } if (handlep->mondevice != NULL) { free(handlep->mondevice); handlep->mondevice = NULL; } if (handlep->device != NULL) { free(handlep->device); handlep->device = NULL; } pcap_cleanup_live_common(handle); } /* * Set the timeout to be used in poll() with memory-mapped packet capture. */ static void set_poll_timeout(struct pcap_linux *handlep) { #ifdef HAVE_TPACKET3 struct utsname utsname; char *version_component, *endp; int major, minor; int broken_tpacket_v3 = 1; /* * Some versions of TPACKET_V3 have annoying bugs/misfeatures * around which we have to work. Determine if we have those * problems or not. */ if (uname(&utsname) == 0) { /* * 3.19 is the first release with a fixed version of * TPACKET_V3. We treat anything before that as * not haveing a fixed version; that may really mean * it has *no* version. */ version_component = utsname.release; major = strtol(version_component, &endp, 10); if (endp != version_component && *endp == '.') { /* * OK, that was a valid major version. * Get the minor version. */ version_component = endp + 1; minor = strtol(version_component, &endp, 10); if (endp != version_component && (*endp == '.' || *endp == '\0')) { /* * OK, that was a valid minor version. * Is this 3.19 or newer? */ if (major >= 4 || (major == 3 && minor >= 19)) { /* Yes. TPACKET_V3 works correctly. */ broken_tpacket_v3 = 0; } } } } #endif if (handlep->timeout == 0) { #ifdef HAVE_TPACKET3 /* * XXX - due to a set of (mis)features in the TPACKET_V3 * kernel code prior to the 3.19 kernel, blocking forever * with a TPACKET_V3 socket can, if few packets are * arriving and passing the socket filter, cause most * packets to be dropped. See libpcap issue #335 for the * full painful story. * * The workaround is to have poll() time out very quickly, * so we grab the frames handed to us, and return them to * the kernel, ASAP. */ if (handlep->tp_version == TPACKET_V3 && broken_tpacket_v3) handlep->poll_timeout = 1; /* don't block for very long */ else #endif handlep->poll_timeout = -1; /* block forever */ } else if (handlep->timeout > 0) { #ifdef HAVE_TPACKET3 /* * For TPACKET_V3, the timeout is handled by the kernel, * so block forever; that way, we don't get extra timeouts. * Don't do that if we have a broken TPACKET_V3, though. */ if (handlep->tp_version == TPACKET_V3 && !broken_tpacket_v3) handlep->poll_timeout = -1; /* block forever, let TPACKET_V3 wake us up */ else #endif handlep->poll_timeout = handlep->timeout; /* block for that amount of time */ } else { /* * Non-blocking mode; we call poll() to pick up error * indications, but we don't want it to wait for * anything. */ handlep->poll_timeout = 0; } } /* * Get a handle for a live capture from the given device. You can * pass NULL as device to get all packages (without link level * information of course). If you pass 1 as promisc the interface * will be set to promiscous mode (XXX: I think this usage should * be deprecated and functions be added to select that later allow * modification of that values -- Torsten). */ static int pcap_activate_linux(pcap_t *handle) { struct pcap_linux *handlep = handle->priv; const char *device; struct ifreq ifr; int status = 0; int ret; device = handle->opt.device; /* * Make sure the name we were handed will fit into the ioctls we * might perform on the device; if not, return a "No such device" * indication, as the Linux kernel shouldn't support creating * a device whose name won't fit into those ioctls. * * "Will fit" means "will fit, complete with a null terminator", * so if the length, which does *not* include the null terminator, * is greater than *or equal to* the size of the field into which * we'll be copying it, that won't fit. */ if (strlen(device) >= sizeof(ifr.ifr_name)) { status = PCAP_ERROR_NO_SUCH_DEVICE; goto fail; } handle->inject_op = pcap_inject_linux; handle->setfilter_op = pcap_setfilter_linux; handle->setdirection_op = pcap_setdirection_linux; handle->set_datalink_op = pcap_set_datalink_linux; handle->getnonblock_op = pcap_getnonblock_fd; handle->setnonblock_op = pcap_setnonblock_fd; handle->cleanup_op = pcap_cleanup_linux; handle->read_op = pcap_read_linux; handle->stats_op = pcap_stats_linux; /* * The "any" device is a special device which causes us not * to bind to a particular device and thus to look at all * devices. */ if (strcmp(device, "any") == 0) { if (handle->opt.promisc) { handle->opt.promisc = 0; /* Just a warning. */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Promiscuous mode not supported on the \"any\" device"); status = PCAP_WARNING_PROMISC_NOTSUP; } } handlep->device = strdup(device); if (handlep->device == NULL) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", pcap_strerror(errno) ); return PCAP_ERROR; } /* copy timeout value */ handlep->timeout = handle->opt.timeout; /* * If we're in promiscuous mode, then we probably want * to see when the interface drops packets too, so get an * initial count from /proc/net/dev */ if (handle->opt.promisc) handlep->proc_dropped = linux_if_drops(handlep->device); /* * Current Linux kernels use the protocol family PF_PACKET to * allow direct access to all packets on the network while * older kernels had a special socket type SOCK_PACKET to * implement this feature. * While this old implementation is kind of obsolete we need * to be compatible with older kernels for a while so we are * trying both methods with the newer method preferred. */ ret = activate_new(handle); if (ret < 0) { /* * Fatal error with the new way; just fail. * ret has the error return; if it's PCAP_ERROR, * handle->errbuf has been set appropriately. */ status = ret; goto fail; } if (ret == 1) { /* * Success. * Try to use memory-mapped access. */ switch (activate_mmap(handle, &status)) { case 1: /* * We succeeded. status has been * set to the status to return, * which might be 0, or might be * a PCAP_WARNING_ value. * * Set the timeout to use in poll() before * returning. */ set_poll_timeout(handlep); return status; case 0: /* * Kernel doesn't support it - just continue * with non-memory-mapped access. */ break; case -1: /* * We failed to set up to use it, or the kernel * supports it, but we failed to enable it. * ret has been set to the error status to * return and, if it's PCAP_ERROR, handle->errbuf * contains the error message. */ status = ret; goto fail; } } else if (ret == 0) { /* Non-fatal error; try old way */ if ((ret = activate_old(handle)) != 1) { /* * Both methods to open the packet socket failed. * Tidy up and report our failure (handle->errbuf * is expected to be set by the functions above). */ status = ret; goto fail; } } /* * We set up the socket, but not with memory-mapped access. */ if (handle->opt.buffer_size != 0) { /* * Set the socket buffer size to the specified value. */ if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, &handle->opt.buffer_size, sizeof(handle->opt.buffer_size)) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SO_RCVBUF: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto fail; } } /* Allocate the buffer */ handle->buffer = malloc(handle->bufsize + handle->offset); if (!handle->buffer) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto fail; } /* * "handle->fd" is a socket, so "select()" and "poll()" * should work on it. */ handle->selectable_fd = handle->fd; return status; fail: pcap_cleanup_linux(handle); return status; } /* * Read at most max_packets from the capture stream and call the callback * for each of them. Returns the number of packets handled or -1 if an * error occured. */ static int pcap_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { /* * Currently, on Linux only one packet is delivered per read, * so we don't loop. */ return pcap_read_packet(handle, callback, user); } static int pcap_set_datalink_linux(pcap_t *handle, int dlt) { handle->linktype = dlt; return 0; } /* * linux_check_direction() * * Do checks based on packet direction. */ static inline int linux_check_direction(const pcap_t *handle, const struct sockaddr_ll *sll) { struct pcap_linux *handlep = handle->priv; if (sll->sll_pkttype == PACKET_OUTGOING) { /* * Outgoing packet. * If this is from the loopback device, reject it; * we'll see the packet as an incoming packet as well, * and we don't want to see it twice. */ if (sll->sll_ifindex == handlep->lo_ifindex) return 0; /* * If this is an outgoing CAN or CAN FD frame, and * the user doesn't only want outgoing packets, * reject it; CAN devices and drivers, and the CAN * stack, always arrange to loop back transmitted * packets, so they also appear as incoming packets. * We don't want duplicate packets, and we can't * easily distinguish packets looped back by the CAN * layer than those received by the CAN layer, so we * eliminate this packet instead. */ if ((sll->sll_protocol == LINUX_SLL_P_CAN || sll->sll_protocol == LINUX_SLL_P_CANFD) && handle->direction != PCAP_D_OUT) return 0; /* * If the user only wants incoming packets, reject it. */ if (handle->direction == PCAP_D_IN) return 0; } else { /* * Incoming packet. * If the user only wants outgoing packets, reject it. */ if (handle->direction == PCAP_D_OUT) return 0; } return 1; } /* * Read a packet from the socket calling the handler provided by * the user. Returns the number of packets received or -1 if an * error occured. */ static int pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) { struct pcap_linux *handlep = handle->priv; u_char *bp; int offset; #ifdef HAVE_PF_PACKET_SOCKETS struct sockaddr_ll from; struct sll_header *hdrp; #else struct sockaddr from; #endif #if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg; union { struct cmsghdr cmsg; char buf[CMSG_SPACE(sizeof(struct tpacket_auxdata))]; } cmsg_buf; #else /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */ socklen_t fromlen; #endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */ int packet_len, caplen; struct pcap_pkthdr pcap_header; struct bpf_aux_data aux_data; #ifdef HAVE_PF_PACKET_SOCKETS /* * If this is a cooked device, leave extra room for a * fake packet header. */ if (handlep->cooked) offset = SLL_HDR_LEN; else offset = 0; #else /* * This system doesn't have PF_PACKET sockets, so it doesn't * support cooked devices. */ offset = 0; #endif /* * Receive a single packet from the kernel. * We ignore EINTR, as that might just be due to a signal * being delivered - if the signal should interrupt the * loop, the signal handler should call pcap_breakloop() * to set handle->break_loop (we ignore it on other * platforms as well). * We also ignore ENETDOWN, so that we can continue to * capture traffic if the interface goes down and comes * back up again; comments in the kernel indicate that * we'll just block waiting for packets if we try to * receive from a socket that delivered ENETDOWN, and, * if we're using a memory-mapped buffer, we won't even * get notified of "network down" events. */ bp = (u_char *)handle->buffer + handle->offset; #if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) msg.msg_name = &from; msg.msg_namelen = sizeof(from); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &cmsg_buf; msg.msg_controllen = sizeof(cmsg_buf); msg.msg_flags = 0; iov.iov_len = handle->bufsize - offset; iov.iov_base = bp + offset; #endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */ do { /* * Has "pcap_breakloop()" been called? */ if (handle->break_loop) { /* * Yes - clear the flag that indicates that it has, * and return PCAP_ERROR_BREAK as an indication that * we were told to break out of the loop. */ handle->break_loop = 0; return PCAP_ERROR_BREAK; } #if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) packet_len = recvmsg(handle->fd, &msg, MSG_TRUNC); #else /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */ fromlen = sizeof(from); packet_len = recvfrom( handle->fd, bp + offset, handle->bufsize - offset, MSG_TRUNC, (struct sockaddr *) &from, &fromlen); #endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */ } while (packet_len == -1 && errno == EINTR); /* Check if an error occured */ if (packet_len == -1) { switch (errno) { case EAGAIN: return 0; /* no packet there */ case ENETDOWN: /* * The device on which we're capturing went away. * * XXX - we should really return * PCAP_ERROR_IFACE_NOT_UP, but pcap_dispatch() * etc. aren't defined to return that. */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "The interface went down"); return PCAP_ERROR; default: pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "recvfrom: %s", pcap_strerror(errno)); return PCAP_ERROR; } } #ifdef HAVE_PF_PACKET_SOCKETS if (!handlep->sock_packet) { /* * Unfortunately, there is a window between socket() and * bind() where the kernel may queue packets from any * interface. If we're bound to a particular interface, * discard packets not from that interface. * * (If socket filters are supported, we could do the * same thing we do when changing the filter; however, * that won't handle packet sockets without socket * filter support, and it's a bit more complicated. * It would save some instructions per packet, however.) */ if (handlep->ifindex != -1 && from.sll_ifindex != handlep->ifindex) return 0; /* * Do checks based on packet direction. * We can only do this if we're using PF_PACKET; the * address returned for SOCK_PACKET is a "sockaddr_pkt" * which lacks the relevant packet type information. */ if (!linux_check_direction(handle, &from)) return 0; } #endif #ifdef HAVE_PF_PACKET_SOCKETS /* * If this is a cooked device, fill in the fake packet header. */ if (handlep->cooked) { /* * Add the length of the fake header to the length * of packet data we read. */ packet_len += SLL_HDR_LEN; hdrp = (struct sll_header *)bp; hdrp->sll_pkttype = map_packet_type_to_sll_type(from.sll_pkttype); hdrp->sll_hatype = htons(from.sll_hatype); hdrp->sll_halen = htons(from.sll_halen); memcpy(hdrp->sll_addr, from.sll_addr, (from.sll_halen > SLL_ADDRLEN) ? SLL_ADDRLEN : from.sll_halen); hdrp->sll_protocol = from.sll_protocol; } #if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) if (handlep->vlan_offset != -1) { for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { struct tpacket_auxdata *aux; unsigned int len; struct vlan_tag *tag; if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) || cmsg->cmsg_level != SOL_PACKET || cmsg->cmsg_type != PACKET_AUXDATA) continue; aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg); #if defined(TP_STATUS_VLAN_VALID) if ((aux->tp_vlan_tci == 0) && !(aux->tp_status & TP_STATUS_VLAN_VALID)) #else if (aux->tp_vlan_tci == 0) /* this is ambigious but without the TP_STATUS_VLAN_VALID flag, there is nothing that we can do */ #endif continue; len = (u_int)packet_len > iov.iov_len ? iov.iov_len : (u_int)packet_len; if (len < (u_int)handlep->vlan_offset) break; /* * Move everything in the header, except the * type field, down VLAN_TAG_LEN bytes, to * allow us to insert the VLAN tag between * that stuff and the type field. */ bp -= VLAN_TAG_LEN; memmove(bp, bp + VLAN_TAG_LEN, handlep->vlan_offset); /* * Now insert the tag. */ tag = (struct vlan_tag *)(bp + handlep->vlan_offset); tag->vlan_tpid = htons(VLAN_TPID(aux, aux)); tag->vlan_tci = htons(aux->tp_vlan_tci); /* store vlan tci to bpf_aux_data struct for userland bpf filter */ #if defined(TP_STATUS_VLAN_VALID) aux_data.vlan_tag = htons(aux->tp_vlan_tci) & 0x0fff; aux_data.vlan_tag_present = (aux->tp_status & TP_STATUS_VLAN_VALID); #endif /* * Add the tag to the packet lengths. */ packet_len += VLAN_TAG_LEN; } } #endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */ #endif /* HAVE_PF_PACKET_SOCKETS */ /* * XXX: According to the kernel source we should get the real * packet len if calling recvfrom with MSG_TRUNC set. It does * not seem to work here :(, but it is supported by this code * anyway. * To be honest the code RELIES on that feature so this is really * broken with 2.2.x kernels. * I spend a day to figure out what's going on and I found out * that the following is happening: * * The packet comes from a random interface and the packet_rcv * hook is called with a clone of the packet. That code inserts * the packet into the receive queue of the packet socket. * If a filter is attached to that socket that filter is run * first - and there lies the problem. The default filter always * cuts the packet at the snaplen: * * # tcpdump -d * (000) ret #68 * * So the packet filter cuts down the packet. The recvfrom call * says "hey, it's only 68 bytes, it fits into the buffer" with * the result that we don't get the real packet length. This * is valid at least until kernel 2.2.17pre6. * * We currently handle this by making a copy of the filter * program, fixing all "ret" instructions with non-zero * operands to have an operand of MAXIMUM_SNAPLEN so that the * filter doesn't truncate the packet, and supplying that modified * filter to the kernel. */ caplen = packet_len; if (caplen > handle->snapshot) caplen = handle->snapshot; /* Run the packet filter if not using kernel filter */ if (handlep->filter_in_userland && handle->fcode.bf_insns) { if (bpf_filter_with_aux_data(handle->fcode.bf_insns, bp, packet_len, caplen, &aux_data) == 0) { /* rejected by filter */ return 0; } } /* Fill in our own header data */ /* get timestamp for this packet */ #if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) if (handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) { if (ioctl(handle->fd, SIOCGSTAMPNS, &pcap_header.ts) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SIOCGSTAMPNS: %s", pcap_strerror(errno)); return PCAP_ERROR; } } else #endif { if (ioctl(handle->fd, SIOCGSTAMP, &pcap_header.ts) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SIOCGSTAMP: %s", pcap_strerror(errno)); return PCAP_ERROR; } } pcap_header.caplen = caplen; pcap_header.len = packet_len; /* * Count the packet. * * Arguably, we should count them before we check the filter, * as on many other platforms "ps_recv" counts packets * handed to the filter rather than packets that passed * the filter, but if filtering is done in the kernel, we * can't get a count of packets that passed the filter, * and that would mean the meaning of "ps_recv" wouldn't * be the same on all Linux systems. * * XXX - it's not the same on all systems in any case; * ideally, we should have a "get the statistics" call * that supplies more counts and indicates which of them * it supplies, so that we supply a count of packets * handed to the filter only on platforms where that * information is available. * * We count them here even if we can get the packet count * from the kernel, as we can only determine at run time * whether we'll be able to get it from the kernel (if * HAVE_TPACKET_STATS isn't defined, we can't get it from * the kernel, but if it is defined, the library might * have been built with a 2.4 or later kernel, but we * might be running on a 2.2[.x] kernel without Alexey * Kuznetzov's turbopacket patches, and thus the kernel * might not be able to supply those statistics). We * could, I guess, try, when opening the socket, to get * the statistics, and if we can not increment the count * here, but it's not clear that always incrementing * the count is more expensive than always testing a flag * in memory. * * We keep the count in "handlep->packets_read", and use that * for "ps_recv" if we can't get the statistics from the kernel. * We do that because, if we *can* get the statistics from * the kernel, we use "handlep->stat.ps_recv" and * "handlep->stat.ps_drop" as running counts, as reading the * statistics from the kernel resets the kernel statistics, * and if we directly increment "handlep->stat.ps_recv" here, * that means it will count packets *twice* on systems where * we can get kernel statistics - once here, and once in * pcap_stats_linux(). */ handlep->packets_read++; /* Call the user supplied callback function */ callback(userdata, &pcap_header, bp); return 1; } static int pcap_inject_linux(pcap_t *handle, const void *buf, size_t size) { struct pcap_linux *handlep = handle->priv; int ret; #ifdef HAVE_PF_PACKET_SOCKETS if (!handlep->sock_packet) { /* PF_PACKET socket */ if (handlep->ifindex == -1) { /* * We don't support sending on the "any" device. */ strlcpy(handle->errbuf, "Sending packets isn't supported on the \"any\" device", PCAP_ERRBUF_SIZE); return (-1); } if (handlep->cooked) { /* * We don't support sending on the "any" device. * * XXX - how do you send on a bound cooked-mode * socket? * Is a "sendto()" required there? */ strlcpy(handle->errbuf, "Sending packets isn't supported in cooked mode", PCAP_ERRBUF_SIZE); return (-1); } } #endif ret = send(handle->fd, buf, size, 0); if (ret == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "send: %s", pcap_strerror(errno)); return (-1); } return (ret); } /* * Get the statistics for the given packet capture handle. * Reports the number of dropped packets iff the kernel supports * the PACKET_STATISTICS "getsockopt()" argument (2.4 and later * kernels, and 2.2[.x] kernels with Alexey Kuznetzov's turbopacket * patches); otherwise, that information isn't available, and we lie * and report 0 as the count of dropped packets. */ static int pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats) { struct pcap_linux *handlep = handle->priv; #ifdef HAVE_TPACKET_STATS #ifdef HAVE_TPACKET3 /* * For sockets using TPACKET_V1 or TPACKET_V2, the extra * stuff at the end of a struct tpacket_stats_v3 will not * be filled in, and we don't look at it so this is OK even * for those sockets. In addition, the PF_PACKET socket * code in the kernel only uses the length parameter to * compute how much data to copy out and to indicate how * much data was copied out, so it's OK to base it on the * size of a struct tpacket_stats. * * XXX - it's probably OK, in fact, to just use a * struct tpacket_stats for V3 sockets, as we don't * care about the tp_freeze_q_cnt stat. */ struct tpacket_stats_v3 kstats; #else /* HAVE_TPACKET3 */ struct tpacket_stats kstats; #endif /* HAVE_TPACKET3 */ socklen_t len = sizeof (struct tpacket_stats); #endif /* HAVE_TPACKET_STATS */ long if_dropped = 0; /* * To fill in ps_ifdrop, we parse /proc/net/dev for the number */ if (handle->opt.promisc) { if_dropped = handlep->proc_dropped; handlep->proc_dropped = linux_if_drops(handlep->device); handlep->stat.ps_ifdrop += (handlep->proc_dropped - if_dropped); } #ifdef HAVE_TPACKET_STATS /* * Try to get the packet counts from the kernel. */ if (getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS, &kstats, &len) > -1) { /* * On systems where the PACKET_STATISTICS "getsockopt()" * argument is supported on PF_PACKET sockets: * * "ps_recv" counts only packets that *passed* the * filter, not packets that didn't pass the filter. * This includes packets later dropped because we * ran out of buffer space. * * "ps_drop" counts packets dropped because we ran * out of buffer space. It doesn't count packets * dropped by the interface driver. It counts only * packets that passed the filter. * * See above for ps_ifdrop. * * Both statistics include packets not yet read from * the kernel by libpcap, and thus not yet seen by * the application. * * In "linux/net/packet/af_packet.c", at least in the * 2.4.9 kernel, "tp_packets" is incremented for every * packet that passes the packet filter *and* is * successfully queued on the socket; "tp_drops" is * incremented for every packet dropped because there's * not enough free space in the socket buffer. * * When the statistics are returned for a PACKET_STATISTICS * "getsockopt()" call, "tp_drops" is added to "tp_packets", * so that "tp_packets" counts all packets handed to * the PF_PACKET socket, including packets dropped because * there wasn't room on the socket buffer - but not * including packets that didn't pass the filter. * * In the BSD BPF, the count of received packets is * incremented for every packet handed to BPF, regardless * of whether it passed the filter. * * We can't make "pcap_stats()" work the same on both * platforms, but the best approximation is to return * "tp_packets" as the count of packets and "tp_drops" * as the count of drops. * * Keep a running total because each call to * getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS, .... * resets the counters to zero. */ handlep->stat.ps_recv += kstats.tp_packets; handlep->stat.ps_drop += kstats.tp_drops; *stats = handlep->stat; return 0; } else { /* * If the error was EOPNOTSUPP, fall through, so that * if you build the library on a system with * "struct tpacket_stats" and run it on a system * that doesn't, it works as it does if the library * is built on a system without "struct tpacket_stats". */ if (errno != EOPNOTSUPP) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "pcap_stats: %s", pcap_strerror(errno)); return -1; } } #endif /* * On systems where the PACKET_STATISTICS "getsockopt()" argument * is not supported on PF_PACKET sockets: * * "ps_recv" counts only packets that *passed* the filter, * not packets that didn't pass the filter. It does not * count packets dropped because we ran out of buffer * space. * * "ps_drop" is not supported. * * "ps_ifdrop" is supported. It will return the number * of drops the interface reports in /proc/net/dev, * if that is available. * * "ps_recv" doesn't include packets not yet read from * the kernel by libpcap. * * We maintain the count of packets processed by libpcap in * "handlep->packets_read", for reasons described in the comment * at the end of pcap_read_packet(). We have no idea how many * packets were dropped by the kernel buffers -- but we know * how many the interface dropped, so we can return that. */ stats->ps_recv = handlep->packets_read; stats->ps_drop = 0; stats->ps_ifdrop = handlep->stat.ps_ifdrop; return 0; } static int add_linux_if(pcap_if_t **devlistp, const char *ifname, int fd, char *errbuf) { const char *p; char name[512]; /* XXX - pick a size */ char *q, *saveq; struct ifreq ifrflags; /* * Get the interface name. */ p = ifname; q = &name[0]; while (*p != '\0' && isascii(*p) && !isspace(*p)) { if (*p == ':') { /* * This could be the separator between a * name and an alias number, or it could be * the separator between a name with no * alias number and the next field. * * If there's a colon after digits, it * separates the name and the alias number, * otherwise it separates the name and the * next field. */ saveq = q; while (isascii(*p) && isdigit(*p)) *q++ = *p++; if (*p != ':') { /* * That was the next field, * not the alias number. */ q = saveq; } break; } else *q++ = *p++; } *q = '\0'; /* * Get the flags for this interface. */ strlcpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) { if (errno == ENXIO || errno == ENODEV) return (0); /* device doesn't actually exist - ignore it */ (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFFLAGS: %.*s: %s", (int)sizeof(ifrflags.ifr_name), ifrflags.ifr_name, pcap_strerror(errno)); return (-1); } /* * Add an entry for this interface, with no addresses. */ if (pcap_add_if(devlistp, name, if_flags_to_pcap_flags(name, ifrflags.ifr_flags), NULL, errbuf) == -1) { /* * Failure. */ return (-1); } return (0); } /* * Get from "/sys/class/net" all interfaces listed there; if they're * already in the list of interfaces we have, that won't add another * instance, but if they're not, that'll add them. * * We don't bother getting any addresses for them; it appears you can't * use SIOCGIFADDR on Linux to get IPv6 addresses for interfaces, and, * although some other types of addresses can be fetched with SIOCGIFADDR, * we don't bother with them for now. * * We also don't fail if we couldn't open "/sys/class/net"; we just leave * the list of interfaces as is, and return 0, so that we can try * scanning /proc/net/dev. * * Otherwise, we return 1 if we don't get an error and -1 if we do. */ static int scan_sys_class_net(pcap_if_t **devlistp, char *errbuf) { DIR *sys_class_net_d; int fd; struct dirent *ent; char subsystem_path[PATH_MAX+1]; struct stat statb; int ret = 1; sys_class_net_d = opendir("/sys/class/net"); if (sys_class_net_d == NULL) { /* * Don't fail if it doesn't exist at all. */ if (errno == ENOENT) return (0); /* * Fail if we got some other error. */ (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Can't open /sys/class/net: %s", pcap_strerror(errno)); return (-1); } /* * Create a socket from which to fetch interface information. */ fd = socket(PF_UNIX, SOCK_RAW, 0); if (fd < 0) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); (void)closedir(sys_class_net_d); return (-1); } for (;;) { errno = 0; ent = readdir(sys_class_net_d); if (ent == NULL) { /* * Error or EOF; if errno != 0, it's an error. */ break; } /* * Ignore "." and "..". */ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue; /* * Ignore plain files; they do not have subdirectories * and thus have no attributes. */ if (ent->d_type == DT_REG) continue; /* * Is there an "ifindex" file under that name? * (We don't care whether it's a directory or * a symlink; older kernels have directories * for devices, newer kernels have symlinks to * directories.) */ pcap_snprintf(subsystem_path, sizeof subsystem_path, "/sys/class/net/%s/ifindex", ent->d_name); if (lstat(subsystem_path, &statb) != 0) { /* * Stat failed. Either there was an error * other than ENOENT, and we don't know if * this is an interface, or it's ENOENT, * and either some part of "/sys/class/net/{if}" * disappeared, in which case it probably means * the interface disappeared, or there's no * "ifindex" file, which means it's not a * network interface. */ continue; } /* * Attempt to add the interface. */ if (add_linux_if(devlistp, &ent->d_name[0], fd, errbuf) == -1) { /* Fail. */ ret = -1; break; } } if (ret != -1) { /* * Well, we didn't fail for any other reason; did we * fail due to an error reading the directory? */ if (errno != 0) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading /sys/class/net: %s", pcap_strerror(errno)); ret = -1; } } (void)close(fd); (void)closedir(sys_class_net_d); return (ret); } /* * Get from "/proc/net/dev" all interfaces listed there; if they're * already in the list of interfaces we have, that won't add another * instance, but if they're not, that'll add them. * * See comments from scan_sys_class_net(). */ static int scan_proc_net_dev(pcap_if_t **devlistp, char *errbuf) { FILE *proc_net_f; int fd; char linebuf[512]; int linenum; char *p; int ret = 0; proc_net_f = fopen("/proc/net/dev", "r"); if (proc_net_f == NULL) { /* * Don't fail if it doesn't exist at all. */ if (errno == ENOENT) return (0); /* * Fail if we got some other error. */ (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Can't open /proc/net/dev: %s", pcap_strerror(errno)); return (-1); } /* * Create a socket from which to fetch interface information. */ fd = socket(PF_UNIX, SOCK_RAW, 0); if (fd < 0) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); (void)fclose(proc_net_f); return (-1); } for (linenum = 1; fgets(linebuf, sizeof linebuf, proc_net_f) != NULL; linenum++) { /* * Skip the first two lines - they're headers. */ if (linenum <= 2) continue; p = &linebuf[0]; /* * Skip leading white space. */ while (*p != '\0' && isascii(*p) && isspace(*p)) p++; if (*p == '\0' || *p == '\n') continue; /* blank line */ /* * Attempt to add the interface. */ if (add_linux_if(devlistp, p, fd, errbuf) == -1) { /* Fail. */ ret = -1; break; } } if (ret != -1) { /* * Well, we didn't fail for any other reason; did we * fail due to an error reading the file? */ if (ferror(proc_net_f)) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading /proc/net/dev: %s", pcap_strerror(errno)); ret = -1; } } (void)close(fd); (void)fclose(proc_net_f); return (ret); } /* * Description string for the "any" device. */ static const char any_descr[] = "Pseudo-device that captures on all interfaces"; /* * A SOCK_PACKET or PF_PACKET socket can be bound to any network interface. */ static int can_be_bound(const char *name _U_) { return (1); } int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { int ret; /* * Get the list of regular interfaces first. */ if (pcap_findalldevs_interfaces(alldevsp, errbuf, can_be_bound) == -1) return (-1); /* failure */ /* * Read "/sys/class/net", and add to the list of interfaces all * interfaces listed there that we don't already have, because, * on Linux, SIOCGIFCONF reports only interfaces with IPv4 addresses, * and even getifaddrs() won't return information about * interfaces with no addresses, so you need to read "/sys/class/net" * to get the names of the rest of the interfaces. */ ret = scan_sys_class_net(alldevsp, errbuf); if (ret == -1) return (-1); /* failed */ if (ret == 0) { /* * No /sys/class/net; try reading /proc/net/dev instead. */ if (scan_proc_net_dev(alldevsp, errbuf) == -1) return (-1); } /* * Add the "any" device. */ if (pcap_add_if(alldevsp, "any", PCAP_IF_UP|PCAP_IF_RUNNING, any_descr, errbuf) < 0) return (-1); return (0); } /* * Attach the given BPF code to the packet capture device. */ static int pcap_setfilter_linux_common(pcap_t *handle, struct bpf_program *filter, int is_mmapped) { struct pcap_linux *handlep; #ifdef SO_ATTACH_FILTER struct sock_fprog fcode; int can_filter_in_kernel; int err = 0; #endif if (!handle) return -1; if (!filter) { strlcpy(handle->errbuf, "setfilter: No filter specified", PCAP_ERRBUF_SIZE); return -1; } handlep = handle->priv; /* Make our private copy of the filter */ if (install_bpf_program(handle, filter) < 0) /* install_bpf_program() filled in errbuf */ return -1; /* * Run user level packet filter by default. Will be overriden if * installing a kernel filter succeeds. */ handlep->filter_in_userland = 1; /* Install kernel level filter if possible */ #ifdef SO_ATTACH_FILTER #ifdef USHRT_MAX if (handle->fcode.bf_len > USHRT_MAX) { /* * fcode.len is an unsigned short for current kernel. * I have yet to see BPF-Code with that much * instructions but still it is possible. So for the * sake of correctness I added this check. */ fprintf(stderr, "Warning: Filter too complex for kernel\n"); fcode.len = 0; fcode.filter = NULL; can_filter_in_kernel = 0; } else #endif /* USHRT_MAX */ { /* * Oh joy, the Linux kernel uses struct sock_fprog instead * of struct bpf_program and of course the length field is * of different size. Pointed out by Sebastian * * Oh, and we also need to fix it up so that all "ret" * instructions with non-zero operands have MAXIMUM_SNAPLEN * as the operand if we're not capturing in memory-mapped * mode, and so that, if we're in cooked mode, all memory- * reference instructions use special magic offsets in * references to the link-layer header and assume that the * link-layer payload begins at 0; "fix_program()" will do * that. */ switch (fix_program(handle, &fcode, is_mmapped)) { case -1: default: /* * Fatal error; just quit. * (The "default" case shouldn't happen; we * return -1 for that reason.) */ return -1; case 0: /* * The program performed checks that we can't make * work in the kernel. */ can_filter_in_kernel = 0; break; case 1: /* * We have a filter that'll work in the kernel. */ can_filter_in_kernel = 1; break; } } /* * NOTE: at this point, we've set both the "len" and "filter" * fields of "fcode". As of the 2.6.32.4 kernel, at least, * those are the only members of the "sock_fprog" structure, * so we initialize every member of that structure. * * If there is anything in "fcode" that is not initialized, * it is either a field added in a later kernel, or it's * padding. * * If a new field is added, this code needs to be updated * to set it correctly. * * If there are no other fields, then: * * if the Linux kernel looks at the padding, it's * buggy; * * if the Linux kernel doesn't look at the padding, * then if some tool complains that we're passing * uninitialized data to the kernel, then the tool * is buggy and needs to understand that it's just * padding. */ if (can_filter_in_kernel) { if ((err = set_kernel_filter(handle, &fcode)) == 0) { /* * Installation succeded - using kernel filter, * so userland filtering not needed. */ handlep->filter_in_userland = 0; } else if (err == -1) /* Non-fatal error */ { /* * Print a warning if we weren't able to install * the filter for a reason other than "this kernel * isn't configured to support socket filters. */ if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) { fprintf(stderr, "Warning: Kernel filter failed: %s\n", pcap_strerror(errno)); } } } /* * If we're not using the kernel filter, get rid of any kernel * filter that might've been there before, e.g. because the * previous filter could work in the kernel, or because some other * code attached a filter to the socket by some means other than * calling "pcap_setfilter()". Otherwise, the kernel filter may * filter out packets that would pass the new userland filter. */ if (handlep->filter_in_userland) { if (reset_kernel_filter(handle) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't remove kernel filter: %s", pcap_strerror(errno)); err = -2; /* fatal error */ } } /* * Free up the copy of the filter that was made by "fix_program()". */ if (fcode.filter != NULL) free(fcode.filter); if (err == -2) /* Fatal error */ return -1; #endif /* SO_ATTACH_FILTER */ return 0; } static int pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter) { return pcap_setfilter_linux_common(handle, filter, 0); } /* * Set direction flag: Which packets do we accept on a forwarding * single device? IN, OUT or both? */ static int pcap_setdirection_linux(pcap_t *handle, pcap_direction_t d) { #ifdef HAVE_PF_PACKET_SOCKETS struct pcap_linux *handlep = handle->priv; if (!handlep->sock_packet) { handle->direction = d; return 0; } #endif /* * We're not using PF_PACKET sockets, so we can't determine * the direction of the packet. */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Setting direction is not supported on SOCK_PACKET sockets"); return -1; } #ifdef HAVE_PF_PACKET_SOCKETS /* * Map the PACKET_ value to a LINUX_SLL_ value; we * want the same numerical value to be used in * the link-layer header even if the numerical values * for the PACKET_ #defines change, so that programs * that look at the packet type field will always be * able to handle DLT_LINUX_SLL captures. */ static short int map_packet_type_to_sll_type(short int sll_pkttype) { switch (sll_pkttype) { case PACKET_HOST: return htons(LINUX_SLL_HOST); case PACKET_BROADCAST: return htons(LINUX_SLL_BROADCAST); case PACKET_MULTICAST: return htons(LINUX_SLL_MULTICAST); case PACKET_OTHERHOST: return htons(LINUX_SLL_OTHERHOST); case PACKET_OUTGOING: return htons(LINUX_SLL_OUTGOING); default: return -1; } } #endif static int is_wifi(int sock_fd #ifndef IW_MODE_MONITOR _U_ #endif , const char *device) { char *pathstr; struct stat statb; #ifdef IW_MODE_MONITOR char errbuf[PCAP_ERRBUF_SIZE]; #endif /* * See if there's a sysfs wireless directory for it. * If so, it's a wireless interface. */ if (asprintf(&pathstr, "/sys/class/net/%s/wireless", device) == -1) { /* * Just give up here. */ return 0; } if (stat(pathstr, &statb) == 0) { free(pathstr); return 1; } free(pathstr); #ifdef IW_MODE_MONITOR /* * OK, maybe it's not wireless, or maybe this kernel doesn't * support sysfs. Try the wireless extensions. */ if (has_wext(sock_fd, device, errbuf) == 1) { /* * It supports the wireless extensions, so it's a Wi-Fi * device. */ return 1; } #endif return 0; } /* * Linux uses the ARP hardware type to identify the type of an * interface. pcap uses the DLT_xxx constants for this. This * function takes a pointer to a "pcap_t", and an ARPHRD_xxx * constant, as arguments, and sets "handle->linktype" to the * appropriate DLT_XXX constant and sets "handle->offset" to * the appropriate value (to make "handle->offset" plus link-layer * header length be a multiple of 4, so that the link-layer payload * will be aligned on a 4-byte boundary when capturing packets). * (If the offset isn't set here, it'll be 0; add code as appropriate * for cases where it shouldn't be 0.) * * If "cooked_ok" is non-zero, we can use DLT_LINUX_SLL and capture * in cooked mode; otherwise, we can't use cooked mode, so we have * to pick some type that works in raw mode, or fail. * * Sets the link type to -1 if unable to map the type. */ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype, const char *device, int cooked_ok) { static const char cdma_rmnet[] = "cdma_rmnet"; switch (arptype) { case ARPHRD_ETHER: /* * For various annoying reasons having to do with DHCP * software, some versions of Android give the mobile- * phone-network interface an ARPHRD_ value of * ARPHRD_ETHER, even though the packets supplied by * that interface have no link-layer header, and begin * with an IP header, so that the ARPHRD_ value should * be ARPHRD_NONE. * * Detect those devices by checking the device name, and * use DLT_RAW for them. */ if (strncmp(device, cdma_rmnet, sizeof cdma_rmnet - 1) == 0) { handle->linktype = DLT_RAW; return; } /* * Is this a real Ethernet device? If so, give it a * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so * that an application can let you choose it, in case you're * capturing DOCSIS traffic that a Cisco Cable Modem * Termination System is putting out onto an Ethernet (it * doesn't put an Ethernet header onto the wire, it puts raw * DOCSIS frames out on the wire inside the low-level * Ethernet framing). * * XXX - are there any other sorts of "fake Ethernet" that * have ARPHRD_ETHER but that shouldn't offer DLT_DOCSIS as * a Cisco CMTS won't put traffic onto it or get traffic * bridged onto it? ISDN is handled in "activate_new()", * as we fall back on cooked mode there, and we use * is_wifi() to check for 802.11 devices; are there any * others? */ if (!is_wifi(sock_fd, device)) { /* * It's not a Wi-Fi device; offer DOCSIS. */ handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (handle->dlt_list != NULL) { handle->dlt_list[0] = DLT_EN10MB; handle->dlt_list[1] = DLT_DOCSIS; handle->dlt_count = 2; } } /* FALLTHROUGH */ case ARPHRD_METRICOM: case ARPHRD_LOOPBACK: handle->linktype = DLT_EN10MB; handle->offset = 2; break; case ARPHRD_EETHER: handle->linktype = DLT_EN3MB; break; case ARPHRD_AX25: handle->linktype = DLT_AX25_KISS; break; case ARPHRD_PRONET: handle->linktype = DLT_PRONET; break; case ARPHRD_CHAOS: handle->linktype = DLT_CHAOS; break; #ifndef ARPHRD_CAN #define ARPHRD_CAN 280 #endif case ARPHRD_CAN: /* * Map this to DLT_LINUX_SLL; that way, CAN frames will * have ETH_P_CAN/LINUX_SLL_P_CAN as the protocol and * CAN FD frames will have ETH_P_CANFD/LINUX_SLL_P_CANFD * as the protocol, so they can be distinguished by the * protocol in the SLL header. */ handle->linktype = DLT_LINUX_SLL; break; #ifndef ARPHRD_IEEE802_TR #define ARPHRD_IEEE802_TR 800 /* From Linux 2.4 */ #endif case ARPHRD_IEEE802_TR: case ARPHRD_IEEE802: handle->linktype = DLT_IEEE802; handle->offset = 2; break; case ARPHRD_ARCNET: handle->linktype = DLT_ARCNET_LINUX; break; #ifndef ARPHRD_FDDI /* From Linux 2.2.13 */ #define ARPHRD_FDDI 774 #endif case ARPHRD_FDDI: handle->linktype = DLT_FDDI; handle->offset = 3; break; #ifndef ARPHRD_ATM /* FIXME: How to #include this? */ #define ARPHRD_ATM 19 #endif case ARPHRD_ATM: /* * The Classical IP implementation in ATM for Linux * supports both what RFC 1483 calls "LLC Encapsulation", * in which each packet has an LLC header, possibly * with a SNAP header as well, prepended to it, and * what RFC 1483 calls "VC Based Multiplexing", in which * different virtual circuits carry different network * layer protocols, and no header is prepended to packets. * * They both have an ARPHRD_ type of ARPHRD_ATM, so * you can't use the ARPHRD_ type to find out whether * captured packets will have an LLC header, and, * while there's a socket ioctl to *set* the encapsulation * type, there's no ioctl to *get* the encapsulation type. * * This means that * * programs that dissect Linux Classical IP frames * would have to check for an LLC header and, * depending on whether they see one or not, dissect * the frame as LLC-encapsulated or as raw IP (I * don't know whether there's any traffic other than * IP that would show up on the socket, or whether * there's any support for IPv6 in the Linux * Classical IP code); * * filter expressions would have to compile into * code that checks for an LLC header and does * the right thing. * * Both of those are a nuisance - and, at least on systems * that support PF_PACKET sockets, we don't have to put * up with those nuisances; instead, we can just capture * in cooked mode. That's what we'll do, if we can. * Otherwise, we'll just fail. */ if (cooked_ok) handle->linktype = DLT_LINUX_SLL; else handle->linktype = -1; break; #ifndef ARPHRD_IEEE80211 /* From Linux 2.4.6 */ #define ARPHRD_IEEE80211 801 #endif case ARPHRD_IEEE80211: handle->linktype = DLT_IEEE802_11; break; #ifndef ARPHRD_IEEE80211_PRISM /* From Linux 2.4.18 */ #define ARPHRD_IEEE80211_PRISM 802 #endif case ARPHRD_IEEE80211_PRISM: handle->linktype = DLT_PRISM_HEADER; break; #ifndef ARPHRD_IEEE80211_RADIOTAP /* new */ #define ARPHRD_IEEE80211_RADIOTAP 803 #endif case ARPHRD_IEEE80211_RADIOTAP: handle->linktype = DLT_IEEE802_11_RADIO; break; case ARPHRD_PPP: /* * Some PPP code in the kernel supplies no link-layer * header whatsoever to PF_PACKET sockets; other PPP * code supplies PPP link-layer headers ("syncppp.c"); * some PPP code might supply random link-layer * headers (PPP over ISDN - there's code in Ethereal, * for example, to cope with PPP-over-ISDN captures * with which the Ethereal developers have had to cope, * heuristically trying to determine which of the * oddball link-layer headers particular packets have). * * As such, we just punt, and run all PPP interfaces * in cooked mode, if we can; otherwise, we just treat * it as DLT_RAW, for now - if somebody needs to capture, * on a 2.0[.x] kernel, on PPP devices that supply a * link-layer header, they'll have to add code here to * map to the appropriate DLT_ type (possibly adding a * new DLT_ type, if necessary). */ if (cooked_ok) handle->linktype = DLT_LINUX_SLL; else { /* * XXX - handle ISDN types here? We can't fall * back on cooked sockets, so we'd have to * figure out from the device name what type of * link-layer encapsulation it's using, and map * that to an appropriate DLT_ value, meaning * we'd map "isdnN" devices to DLT_RAW (they * supply raw IP packets with no link-layer * header) and "isdY" devices to a new DLT_I4L_IP * type that has only an Ethernet packet type as * a link-layer header. * * But sometimes we seem to get random crap * in the link-layer header when capturing on * ISDN devices.... */ handle->linktype = DLT_RAW; } break; #ifndef ARPHRD_CISCO #define ARPHRD_CISCO 513 /* previously ARPHRD_HDLC */ #endif case ARPHRD_CISCO: handle->linktype = DLT_C_HDLC; break; /* Not sure if this is correct for all tunnels, but it * works for CIPE */ case ARPHRD_TUNNEL: #ifndef ARPHRD_SIT #define ARPHRD_SIT 776 /* From Linux 2.2.13 */ #endif case ARPHRD_SIT: case ARPHRD_CSLIP: case ARPHRD_SLIP6: case ARPHRD_CSLIP6: case ARPHRD_ADAPT: case ARPHRD_SLIP: #ifndef ARPHRD_RAWHDLC #define ARPHRD_RAWHDLC 518 #endif case ARPHRD_RAWHDLC: #ifndef ARPHRD_DLCI #define ARPHRD_DLCI 15 #endif case ARPHRD_DLCI: /* * XXX - should some of those be mapped to DLT_LINUX_SLL * instead? Should we just map all of them to DLT_LINUX_SLL? */ handle->linktype = DLT_RAW; break; #ifndef ARPHRD_FRAD #define ARPHRD_FRAD 770 #endif case ARPHRD_FRAD: handle->linktype = DLT_FRELAY; break; case ARPHRD_LOCALTLK: handle->linktype = DLT_LTALK; break; case 18: /* * RFC 4338 defines an encapsulation for IP and ARP * packets that's compatible with the RFC 2625 * encapsulation, but that uses a different ARP * hardware type and hardware addresses. That * ARP hardware type is 18; Linux doesn't define * any ARPHRD_ value as 18, but if it ever officially * supports RFC 4338-style IP-over-FC, it should define * one. * * For now, we map it to DLT_IP_OVER_FC, in the hopes * that this will encourage its use in the future, * should Linux ever officially support RFC 4338-style * IP-over-FC. */ handle->linktype = DLT_IP_OVER_FC; break; #ifndef ARPHRD_FCPP #define ARPHRD_FCPP 784 #endif case ARPHRD_FCPP: #ifndef ARPHRD_FCAL #define ARPHRD_FCAL 785 #endif case ARPHRD_FCAL: #ifndef ARPHRD_FCPL #define ARPHRD_FCPL 786 #endif case ARPHRD_FCPL: #ifndef ARPHRD_FCFABRIC #define ARPHRD_FCFABRIC 787 #endif case ARPHRD_FCFABRIC: /* * Back in 2002, Donald Lee at Cray wanted a DLT_ for * IP-over-FC: * * http://www.mail-archive.com/tcpdump-workers@sandelman.ottawa.on.ca/msg01043.html * * and one was assigned. * * In a later private discussion (spun off from a message * on the ethereal-users list) on how to get that DLT_ * value in libpcap on Linux, I ended up deciding that * the best thing to do would be to have him tweak the * driver to set the ARPHRD_ value to some ARPHRD_FCxx * type, and map all those types to DLT_IP_OVER_FC: * * I've checked into the libpcap and tcpdump CVS tree * support for DLT_IP_OVER_FC. In order to use that, * you'd have to modify your modified driver to return * one of the ARPHRD_FCxxx types, in "fcLINUXfcp.c" - * change it to set "dev->type" to ARPHRD_FCFABRIC, for * example (the exact value doesn't matter, it can be * any of ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, or * ARPHRD_FCFABRIC). * * 11 years later, Christian Svensson wanted to map * various ARPHRD_ values to DLT_FC_2 and * DLT_FC_2_WITH_FRAME_DELIMS for raw Fibre Channel * frames: * * https://github.com/mcr/libpcap/pull/29 * * There doesn't seem to be any network drivers that uses * any of the ARPHRD_FC* values for IP-over-FC, and * it's not exactly clear what the "Dummy types for non * ARP hardware" are supposed to mean (link-layer * header type? Physical network type?), so it's * not exactly clear why the ARPHRD_FC* types exist * in the first place. * * For now, we map them to DLT_FC_2, and provide an * option of DLT_FC_2_WITH_FRAME_DELIMS, as well as * DLT_IP_OVER_FC just in case there's some old * driver out there that uses one of those types for * IP-over-FC on which somebody wants to capture * packets. */ handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (handle->dlt_list != NULL) { handle->dlt_list[0] = DLT_FC_2; handle->dlt_list[1] = DLT_FC_2_WITH_FRAME_DELIMS; handle->dlt_list[2] = DLT_IP_OVER_FC; handle->dlt_count = 3; } handle->linktype = DLT_FC_2; break; #ifndef ARPHRD_IRDA #define ARPHRD_IRDA 783 #endif case ARPHRD_IRDA: /* Don't expect IP packet out of this interfaces... */ handle->linktype = DLT_LINUX_IRDA; /* We need to save packet direction for IrDA decoding, * so let's use "Linux-cooked" mode. Jean II * * XXX - this is handled in activate_new(). */ /* handlep->cooked = 1; */ break; /* ARPHRD_LAPD is unofficial and randomly allocated, if reallocation * is needed, please report it to */ #ifndef ARPHRD_LAPD #define ARPHRD_LAPD 8445 #endif case ARPHRD_LAPD: /* Don't expect IP packet out of this interfaces... */ handle->linktype = DLT_LINUX_LAPD; break; #ifndef ARPHRD_NONE #define ARPHRD_NONE 0xFFFE #endif case ARPHRD_NONE: /* * No link-layer header; packets are just IP * packets, so use DLT_RAW. */ handle->linktype = DLT_RAW; break; #ifndef ARPHRD_IEEE802154 #define ARPHRD_IEEE802154 804 #endif case ARPHRD_IEEE802154: handle->linktype = DLT_IEEE802_15_4_NOFCS; break; #ifndef ARPHRD_NETLINK #define ARPHRD_NETLINK 824 #endif case ARPHRD_NETLINK: handle->linktype = DLT_NETLINK; /* * We need to use cooked mode, so that in sll_protocol we * pick up the netlink protocol type such as NETLINK_ROUTE, * NETLINK_GENERIC, NETLINK_FIB_LOOKUP, etc. * * XXX - this is handled in activate_new(). */ /* handlep->cooked = 1; */ break; default: handle->linktype = -1; break; } } /* ===== Functions to interface to the newer kernels ================== */ /* * Try to open a packet socket using the new kernel PF_PACKET interface. * Returns 1 on success, 0 on an error that means the new interface isn't * present (so the old SOCK_PACKET interface should be tried), and a * PCAP_ERROR_ value on an error that means that the old mechanism won't * work either (so it shouldn't be tried). */ static int activate_new(pcap_t *handle) { #ifdef HAVE_PF_PACKET_SOCKETS struct pcap_linux *handlep = handle->priv; const char *device = handle->opt.device; int is_any_device = (strcmp(device, "any") == 0); int sock_fd = -1, arptype; #ifdef HAVE_PACKET_AUXDATA int val; #endif int err = 0; struct packet_mreq mr; #if defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT) int bpf_extensions; socklen_t len = sizeof(bpf_extensions); #endif /* * Open a socket with protocol family packet. If the * "any" device was specified, we open a SOCK_DGRAM * socket for the cooked interface, otherwise we first * try a SOCK_RAW socket for the raw interface. */ sock_fd = is_any_device ? socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)) : socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (sock_fd == -1) { if (errno == EINVAL || errno == EAFNOSUPPORT) { /* * We don't support PF_PACKET/SOCK_whatever * sockets; try the old mechanism. */ return 0; } pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno) ); if (errno == EPERM || errno == EACCES) { /* * You don't have permission to open the * socket. */ return PCAP_ERROR_PERM_DENIED; } else { /* * Other error. */ return PCAP_ERROR; } } /* It seems the kernel supports the new interface. */ handlep->sock_packet = 0; /* * Get the interface index of the loopback device. * If the attempt fails, don't fail, just set the * "handlep->lo_ifindex" to -1. * * XXX - can there be more than one device that loops * packets back, i.e. devices other than "lo"? If so, * we'd need to find them all, and have an array of * indices for them, and check all of them in * "pcap_read_packet()". */ handlep->lo_ifindex = iface_get_id(sock_fd, "lo", handle->errbuf); /* * Default value for offset to align link-layer payload * on a 4-byte boundary. */ handle->offset = 0; /* * What kind of frames do we have to deal with? Fall back * to cooked mode if we have an unknown interface type * or a type we know doesn't work well in raw mode. */ if (!is_any_device) { /* Assume for now we don't need cooked mode. */ handlep->cooked = 0; if (handle->opt.rfmon) { /* * We were asked to turn on monitor mode. * Do so before we get the link-layer type, * because entering monitor mode could change * the link-layer type. */ err = enter_rfmon_mode(handle, sock_fd, device); if (err < 0) { /* Hard failure */ close(sock_fd); return err; } if (err == 0) { /* * Nothing worked for turning monitor mode * on. */ close(sock_fd); return PCAP_ERROR_RFMON_NOTSUP; } /* * Either monitor mode has been turned on for * the device, or we've been given a different * device to open for monitor mode. If we've * been given a different device, use it. */ if (handlep->mondevice != NULL) device = handlep->mondevice; } arptype = iface_get_arptype(sock_fd, device, handle->errbuf); if (arptype < 0) { close(sock_fd); return arptype; } map_arphrd_to_dlt(handle, sock_fd, arptype, device, 1); if (handle->linktype == -1 || handle->linktype == DLT_LINUX_SLL || handle->linktype == DLT_LINUX_IRDA || handle->linktype == DLT_LINUX_LAPD || handle->linktype == DLT_NETLINK || (handle->linktype == DLT_EN10MB && (strncmp("isdn", device, 4) == 0 || strncmp("isdY", device, 4) == 0))) { /* * Unknown interface type (-1), or a * device we explicitly chose to run * in cooked mode (e.g., PPP devices), * or an ISDN device (whose link-layer * type we can only determine by using * APIs that may be different on different * kernels) - reopen in cooked mode. */ if (close(sock_fd) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "close: %s", pcap_strerror(errno)); return PCAP_ERROR; } sock_fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)); if (sock_fd == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); if (errno == EPERM || errno == EACCES) { /* * You don't have permission to * open the socket. */ return PCAP_ERROR_PERM_DENIED; } else { /* * Other error. */ return PCAP_ERROR; } } handlep->cooked = 1; /* * Get rid of any link-layer type list * we allocated - this only supports cooked * capture. */ if (handle->dlt_list != NULL) { free(handle->dlt_list); handle->dlt_list = NULL; handle->dlt_count = 0; } if (handle->linktype == -1) { /* * Warn that we're falling back on * cooked mode; we may want to * update "map_arphrd_to_dlt()" * to handle the new type. */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "arptype %d not " "supported by libpcap - " "falling back to cooked " "socket", arptype); } /* * IrDA capture is not a real "cooked" capture, * it's IrLAP frames, not IP packets. The * same applies to LAPD capture. */ if (handle->linktype != DLT_LINUX_IRDA && handle->linktype != DLT_LINUX_LAPD && handle->linktype != DLT_NETLINK) handle->linktype = DLT_LINUX_SLL; } handlep->ifindex = iface_get_id(sock_fd, device, handle->errbuf); if (handlep->ifindex == -1) { close(sock_fd); return PCAP_ERROR; } if ((err = iface_bind(sock_fd, handlep->ifindex, handle->errbuf)) != 1) { close(sock_fd); if (err < 0) return err; else return 0; /* try old mechanism */ } } else { /* * The "any" device. */ if (handle->opt.rfmon) { /* * It doesn't support monitor mode. */ close(sock_fd); return PCAP_ERROR_RFMON_NOTSUP; } /* * It uses cooked mode. */ handlep->cooked = 1; handle->linktype = DLT_LINUX_SLL; /* * We're not bound to a device. * For now, we're using this as an indication * that we can't transmit; stop doing that only * if we figure out how to transmit in cooked * mode. */ handlep->ifindex = -1; } /* * Select promiscuous mode on if "promisc" is set. * * Do not turn allmulti mode on if we don't select * promiscuous mode - on some devices (e.g., Orinoco * wireless interfaces), allmulti mode isn't supported * and the driver implements it by turning promiscuous * mode on, and that screws up the operation of the * card as a normal networking interface, and on no * other platform I know of does starting a non- * promiscuous capture affect which multicast packets * are received by the interface. */ /* * Hmm, how can we set promiscuous mode on all interfaces? * I am not sure if that is possible at all. For now, we * silently ignore attempts to turn promiscuous mode on * for the "any" device (so you don't have to explicitly * disable it in programs such as tcpdump). */ if (!is_any_device && handle->opt.promisc) { memset(&mr, 0, sizeof(mr)); mr.mr_ifindex = handlep->ifindex; mr.mr_type = PACKET_MR_PROMISC; if (setsockopt(sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "setsockopt: %s", pcap_strerror(errno)); close(sock_fd); return PCAP_ERROR; } } /* Enable auxillary data if supported and reserve room for * reconstructing VLAN headers. */ #ifdef HAVE_PACKET_AUXDATA val = 1; if (setsockopt(sock_fd, SOL_PACKET, PACKET_AUXDATA, &val, sizeof(val)) == -1 && errno != ENOPROTOOPT) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "setsockopt: %s", pcap_strerror(errno)); close(sock_fd); return PCAP_ERROR; } handle->offset += VLAN_TAG_LEN; #endif /* HAVE_PACKET_AUXDATA */ /* * This is a 2.2[.x] or later kernel (we know that * because we're not using a SOCK_PACKET socket - * PF_PACKET is supported only in 2.2 and later * kernels). * * We can safely pass "recvfrom()" a byte count * based on the snapshot length. * * If we're in cooked mode, make the snapshot length * large enough to hold a "cooked mode" header plus * 1 byte of packet data (so we don't pass a byte * count of 0 to "recvfrom()"). */ if (handlep->cooked) { if (handle->snapshot < SLL_HDR_LEN + 1) handle->snapshot = SLL_HDR_LEN + 1; } handle->bufsize = handle->snapshot; /* * Set the offset at which to insert VLAN tags. * That should be the offset of the type field. */ switch (handle->linktype) { case DLT_EN10MB: /* * The type field is after the destination and source * MAC address. */ handlep->vlan_offset = 2 * ETH_ALEN; break; case DLT_LINUX_SLL: /* * The type field is in the last 2 bytes of the * DLT_LINUX_SLL header. */ handlep->vlan_offset = SLL_HDR_LEN - 2; break; default: handlep->vlan_offset = -1; /* unknown */ break; } #if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) if (handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) { int nsec_tstamps = 1; if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, &nsec_tstamps, sizeof(nsec_tstamps)) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "setsockopt: unable to set SO_TIMESTAMPNS"); close(sock_fd); return PCAP_ERROR; } } #endif /* defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) */ /* * We've succeeded. Save the socket FD in the pcap structure. */ handle->fd = sock_fd; #if defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT) /* * Can we generate special code for VLAN checks? * (XXX - what if we need the special code but it's not supported * by the OS? Is that possible?) */ if (getsockopt(sock_fd, SOL_SOCKET, SO_BPF_EXTENSIONS, &bpf_extensions, &len) == 0) { if (bpf_extensions >= SKF_AD_VLAN_TAG_PRESENT) { /* * Yes, we can. Request that we do so. */ handle->bpf_codegen_flags |= BPF_SPECIAL_VLAN_HANDLING; } } #endif /* defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT) */ return 1; #else /* HAVE_PF_PACKET_SOCKETS */ strlcpy(ebuf, "New packet capturing interface not supported by build " "environment", PCAP_ERRBUF_SIZE); return 0; #endif /* HAVE_PF_PACKET_SOCKETS */ } #ifdef HAVE_PACKET_RING /* * Attempt to activate with memory-mapped access. * * On success, returns 1, and sets *status to 0 if there are no warnings * or to a PCAP_WARNING_ code if there is a warning. * * On failure due to lack of support for memory-mapped capture, returns * 0. * * On error, returns -1, and sets *status to the appropriate error code; * if that is PCAP_ERROR, sets handle->errbuf to the appropriate message. */ static int activate_mmap(pcap_t *handle, int *status) { struct pcap_linux *handlep = handle->priv; int ret; /* * Attempt to allocate a buffer to hold the contents of one * packet, for use by the oneshot callback. */ handlep->oneshot_buffer = malloc(handle->snapshot); if (handlep->oneshot_buffer == NULL) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't allocate oneshot buffer: %s", pcap_strerror(errno)); *status = PCAP_ERROR; return -1; } if (handle->opt.buffer_size == 0) { /* by default request 2M for the ring buffer */ handle->opt.buffer_size = 2*1024*1024; } ret = prepare_tpacket_socket(handle); if (ret == -1) { free(handlep->oneshot_buffer); *status = PCAP_ERROR; return ret; } ret = create_ring(handle, status); if (ret == 0) { /* * We don't support memory-mapped capture; our caller * will fall back on reading from the socket. */ free(handlep->oneshot_buffer); return 0; } if (ret == -1) { /* * Error attempting to enable memory-mapped capture; * fail. create_ring() has set *status. */ free(handlep->oneshot_buffer); return -1; } /* * Success. *status has been set either to 0 if there are no * warnings or to a PCAP_WARNING_ value if there is a warning. * * Override some defaults and inherit the other fields from * activate_new. * handle->offset is used to get the current position into the rx ring. * handle->cc is used to store the ring size. */ switch (handlep->tp_version) { case TPACKET_V1: handle->read_op = pcap_read_linux_mmap_v1; break; case TPACKET_V1_64: handle->read_op = pcap_read_linux_mmap_v1_64; break; #ifdef HAVE_TPACKET2 case TPACKET_V2: handle->read_op = pcap_read_linux_mmap_v2; break; #endif #ifdef HAVE_TPACKET3 case TPACKET_V3: handle->read_op = pcap_read_linux_mmap_v3; break; #endif } handle->cleanup_op = pcap_cleanup_linux_mmap; handle->setfilter_op = pcap_setfilter_linux_mmap; handle->setnonblock_op = pcap_setnonblock_mmap; handle->getnonblock_op = pcap_getnonblock_mmap; handle->oneshot_callback = pcap_oneshot_mmap; handle->selectable_fd = handle->fd; return 1; } #else /* HAVE_PACKET_RING */ static int activate_mmap(pcap_t *handle _U_, int *status _U_) { return 0; } #endif /* HAVE_PACKET_RING */ #ifdef HAVE_PACKET_RING #if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3) /* * Attempt to set the socket to the specified version of the memory-mapped * header. * * Return 0 if we succeed; return 1 if we fail because that version isn't * supported; return -1 on any other error, and set handle->errbuf. */ static int init_tpacket(pcap_t *handle, int version, const char *version_str) { struct pcap_linux *handlep = handle->priv; int val = version; socklen_t len = sizeof(val); /* * Probe whether kernel supports the specified TPACKET version; * this also gets the length of the header for that version. */ if (getsockopt(handle->fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { if (errno == ENOPROTOOPT || errno == EINVAL) return 1; /* no */ /* Failed to even find out; this is a fatal error. */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't get %s header len on packet socket: %s", version_str, pcap_strerror(errno)); return -1; } handlep->tp_hdrlen = val; val = version; if (setsockopt(handle->fd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val)) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't activate %s on packet socket: %s", version_str, pcap_strerror(errno)); return -1; } handlep->tp_version = version; /* Reserve space for VLAN tag reconstruction */ val = VLAN_TAG_LEN; if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, &val, sizeof(val)) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't set up reserve on packet socket: %s", pcap_strerror(errno)); return -1; } return 0; } #endif /* defined HAVE_TPACKET2 || defined HAVE_TPACKET3 */ /* * If the instruction set for which we're compiling has both 32-bit * and 64-bit versions, and Linux support for the 64-bit version * predates TPACKET_V2, define ISA_64_BIT as the .machine value * you get from uname() for the 64-bit version. Otherwise, leave * it undefined. (This includes ARM, which has a 64-bit version, * but Linux support for it appeared well after TPACKET_V2 support * did, so there should never be a case where 32-bit ARM code is * running o a 64-bit kernel that only supports TPACKET_V1.) * * If we've omitted your favorite such architecture, please contribute * a patch. (No patch is needed for architectures that are 32-bit-only * or for which Linux has no support for 32-bit userland - or for which, * as noted, 64-bit support appeared in Linux after TPACKET_V2 support * did.) */ #if defined(__i386__) #define ISA_64_BIT "x86_64" #elif defined(__ppc__) #define ISA_64_BIT "ppc64" #elif defined(__sparc__) #define ISA_64_BIT "sparc64" #elif defined(__s390__) #define ISA_64_BIT "s390x" #elif defined(__mips__) #define ISA_64_BIT "mips64" #elif defined(__hppa__) #define ISA_64_BIT "parisc64" #endif /* * Attempt to set the socket to version 3 of the memory-mapped header and, * if that fails because version 3 isn't supported, attempt to fall * back to version 2. If version 2 isn't supported, just leave it at * version 1. * * Return 1 if we succeed or if we fail because neither version 2 nor 3 is * supported; return -1 on any other error, and set handle->errbuf. */ static int prepare_tpacket_socket(pcap_t *handle) { struct pcap_linux *handlep = handle->priv; #if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3) int ret; #endif #ifdef HAVE_TPACKET3 /* * Try setting the version to TPACKET_V3. * * The only mode in which buffering is done on PF_PACKET * sockets, so that packets might not be delivered * immediately, is TPACKET_V3 mode. * * The buffering cannot be disabled in that mode, so * if the user has requested immediate mode, we don't * use TPACKET_V3. */ if (!handle->opt.immediate) { ret = init_tpacket(handle, TPACKET_V3, "TPACKET_V3"); if (ret == 0) { /* * Success. */ return 1; } if (ret == -1) { /* * We failed for some reason other than "the * kernel doesn't support TPACKET_V3". */ return -1; } } #endif /* HAVE_TPACKET3 */ #ifdef HAVE_TPACKET2 /* * Try setting the version to TPACKET_V2. */ ret = init_tpacket(handle, TPACKET_V2, "TPACKET_V2"); if (ret == 0) { /* * Success. */ return 1; } if (ret == -1) { /* * We failed for some reason other than "the * kernel doesn't support TPACKET_V2". */ return -1; } #endif /* HAVE_TPACKET2 */ /* * OK, we're using TPACKET_V1, as that's all the kernel supports. */ handlep->tp_version = TPACKET_V1; handlep->tp_hdrlen = sizeof(struct tpacket_hdr); #ifdef ISA_64_BIT /* * 32-bit userspace + 64-bit kernel + TPACKET_V1 are not compatible with * each other due to platform-dependent data type size differences. * * If we have a 32-bit userland and a 64-bit kernel, use an * internally-defined TPACKET_V1_64, with which we use a 64-bit * version of the data structures. */ if (sizeof(long) == 4) { /* * This is 32-bit code. */ struct utsname utsname; if (uname(&utsname) == -1) { /* * Failed. */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "uname failed: %s", pcap_strerror(errno)); return -1; } if (strcmp(utsname.machine, ISA_64_BIT) == 0) { /* * uname() tells us the machine is 64-bit, * so we presumably have a 64-bit kernel. * * XXX - this presumes that uname() won't lie * in 32-bit code and claim that the machine * has the 32-bit version of the ISA. */ handlep->tp_version = TPACKET_V1_64; handlep->tp_hdrlen = sizeof(struct tpacket_hdr_64); } } #endif return 1; } /* * Attempt to set up memory-mapped access. * * On success, returns 1, and sets *status to 0 if there are no warnings * or to a PCAP_WARNING_ code if there is a warning. * * On failure due to lack of support for memory-mapped capture, returns * 0. * * On error, returns -1, and sets *status to the appropriate error code; * if that is PCAP_ERROR, sets handle->errbuf to the appropriate message. */ static int create_ring(pcap_t *handle, int *status) { struct pcap_linux *handlep = handle->priv; unsigned i, j, frames_per_block; #ifdef HAVE_TPACKET3 /* * For sockets using TPACKET_V1 or TPACKET_V2, the extra * stuff at the end of a struct tpacket_req3 will be * ignored, so this is OK even for those sockets. */ struct tpacket_req3 req; #else struct tpacket_req req; #endif socklen_t len; unsigned int sk_type, tp_reserve, maclen, tp_hdrlen, netoff, macoff; unsigned int frame_size; /* * Start out assuming no warnings or errors. */ *status = 0; switch (handlep->tp_version) { case TPACKET_V1: case TPACKET_V1_64: #ifdef HAVE_TPACKET2 case TPACKET_V2: #endif /* Note that with large snapshot length (say 64K, which is * the default for recent versions of tcpdump, the value that * "-s 0" has given for a long time with tcpdump, and the * default in Wireshark/TShark/dumpcap), if we use the snapshot * length to calculate the frame length, only a few frames * will be available in the ring even with pretty * large ring size (and a lot of memory will be unused). * * Ideally, we should choose a frame length based on the * minimum of the specified snapshot length and the maximum * packet size. That's not as easy as it sounds; consider, * for example, an 802.11 interface in monitor mode, where * the frame would include a radiotap header, where the * maximum radiotap header length is device-dependent. * * So, for now, we just do this for Ethernet devices, where * there's no metadata header, and the link-layer header is * fixed length. We can get the maximum packet size by * adding 18, the Ethernet header length plus the CRC length * (just in case we happen to get the CRC in the packet), to * the MTU of the interface; we fetch the MTU in the hopes * that it reflects support for jumbo frames. (Even if the * interface is just being used for passive snooping, the * driver might set the size of buffers in the receive ring * based on the MTU, so that the MTU limits the maximum size * of packets that we can receive.) * * We don't do that if segmentation/fragmentation or receive * offload are enabled, so we don't get rudely surprised by * "packets" bigger than the MTU. */ frame_size = handle->snapshot; if (handle->linktype == DLT_EN10MB) { int mtu; int offload; offload = iface_get_offload(handle); if (offload == -1) { *status = PCAP_ERROR; return -1; } if (!offload) { mtu = iface_get_mtu(handle->fd, handle->opt.device, handle->errbuf); if (mtu == -1) { *status = PCAP_ERROR; return -1; } if (frame_size > (unsigned int)mtu + 18) frame_size = (unsigned int)mtu + 18; } } /* NOTE: calculus matching those in tpacket_rcv() * in linux-2.6/net/packet/af_packet.c */ len = sizeof(sk_type); if (getsockopt(handle->fd, SOL_SOCKET, SO_TYPE, &sk_type, &len) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "getsockopt: %s", pcap_strerror(errno)); *status = PCAP_ERROR; return -1; } #ifdef PACKET_RESERVE len = sizeof(tp_reserve); if (getsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, &tp_reserve, &len) < 0) { if (errno != ENOPROTOOPT) { /* * ENOPROTOOPT means "kernel doesn't support * PACKET_RESERVE", in which case we fall back * as best we can. */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "getsockopt: %s", pcap_strerror(errno)); *status = PCAP_ERROR; return -1; } tp_reserve = 0; /* older kernel, reserve not supported */ } #else tp_reserve = 0; /* older kernel, reserve not supported */ #endif maclen = (sk_type == SOCK_DGRAM) ? 0 : MAX_LINKHEADER_SIZE; /* XXX: in the kernel maclen is calculated from * LL_ALLOCATED_SPACE(dev) and vnet_hdr.hdr_len * in: packet_snd() in linux-2.6/net/packet/af_packet.c * then packet_alloc_skb() in linux-2.6/net/packet/af_packet.c * then sock_alloc_send_pskb() in linux-2.6/net/core/sock.c * but I see no way to get those sizes in userspace, * like for instance with an ifreq ioctl(); * the best thing I've found so far is MAX_HEADER in * the kernel part of linux-2.6/include/linux/netdevice.h * which goes up to 128+48=176; since pcap-linux.c * defines a MAX_LINKHEADER_SIZE of 256 which is * greater than that, let's use it.. maybe is it even * large enough to directly replace macoff.. */ tp_hdrlen = TPACKET_ALIGN(handlep->tp_hdrlen) + sizeof(struct sockaddr_ll) ; netoff = TPACKET_ALIGN(tp_hdrlen + (maclen < 16 ? 16 : maclen)) + tp_reserve; /* NOTE: AFAICS tp_reserve may break the TPACKET_ALIGN * of netoff, which contradicts * linux-2.6/Documentation/networking/packet_mmap.txt * documenting that: * "- Gap, chosen so that packet data (Start+tp_net) * aligns to TPACKET_ALIGNMENT=16" */ /* NOTE: in linux-2.6/include/linux/skbuff.h: * "CPUs often take a performance hit * when accessing unaligned memory locations" */ macoff = netoff - maclen; req.tp_frame_size = TPACKET_ALIGN(macoff + frame_size); req.tp_frame_nr = handle->opt.buffer_size/req.tp_frame_size; break; #ifdef HAVE_TPACKET3 case TPACKET_V3: /* The "frames" for this are actually buffers that * contain multiple variable-sized frames. * * We pick a "frame" size of 128K to leave enough * room for at least one reasonably-sized packet * in the "frame". */ req.tp_frame_size = MAXIMUM_SNAPLEN; req.tp_frame_nr = handle->opt.buffer_size/req.tp_frame_size; break; #endif default: pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Internal error: unknown TPACKET_ value %u", handlep->tp_version); *status = PCAP_ERROR; return -1; } /* compute the minumum block size that will handle this frame. * The block has to be page size aligned. * The max block size allowed by the kernel is arch-dependent and * it's not explicitly checked here. */ req.tp_block_size = getpagesize(); while (req.tp_block_size < req.tp_frame_size) req.tp_block_size <<= 1; frames_per_block = req.tp_block_size/req.tp_frame_size; /* * PACKET_TIMESTAMP was added after linux/net_tstamp.h was, * so we check for PACKET_TIMESTAMP. We check for * linux/net_tstamp.h just in case a system somehow has * PACKET_TIMESTAMP but not linux/net_tstamp.h; that might * be unnecessary. * * SIOCSHWTSTAMP was introduced in the patch that introduced * linux/net_tstamp.h, so we don't bother checking whether * SIOCSHWTSTAMP is defined (if your Linux system has * linux/net_tstamp.h but doesn't define SIOCSHWTSTAMP, your * Linux system is badly broken). */ #if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) /* * If we were told to do so, ask the kernel and the driver * to use hardware timestamps. * * Hardware timestamps are only supported with mmapped * captures. */ if (handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER || handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER_UNSYNCED) { struct hwtstamp_config hwconfig; struct ifreq ifr; int timesource; /* * Ask for hardware time stamps on all packets, * including transmitted packets. */ memset(&hwconfig, 0, sizeof(hwconfig)); hwconfig.tx_type = HWTSTAMP_TX_ON; hwconfig.rx_filter = HWTSTAMP_FILTER_ALL; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, handle->opt.device, sizeof(ifr.ifr_name)); ifr.ifr_data = (void *)&hwconfig; if (ioctl(handle->fd, SIOCSHWTSTAMP, &ifr) < 0) { switch (errno) { case EPERM: /* * Treat this as an error, as the * user should try to run this * with the appropriate privileges - * and, if they can't, shouldn't * try requesting hardware time stamps. */ *status = PCAP_ERROR_PERM_DENIED; return -1; case EOPNOTSUPP: case ERANGE: /* * Treat this as a warning, as the * only way to fix the warning is to * get an adapter that supports hardware * time stamps for *all* packets. * (ERANGE means "we support hardware * time stamps, but for packets matching * that particular filter", so it means * "we don't support hardware time stamps * for all incoming packets" here.) * * We'll just fall back on the standard * host time stamps. */ *status = PCAP_WARNING_TSTAMP_TYPE_NOTSUP; break; default: pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SIOCSHWTSTAMP failed: %s", pcap_strerror(errno)); *status = PCAP_ERROR; return -1; } } else { /* * Well, that worked. Now specify the type of * hardware time stamp we want for this * socket. */ if (handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER) { /* * Hardware timestamp, synchronized * with the system clock. */ timesource = SOF_TIMESTAMPING_SYS_HARDWARE; } else { /* * PCAP_TSTAMP_ADAPTER_UNSYNCED - hardware * timestamp, not synchronized with the * system clock. */ timesource = SOF_TIMESTAMPING_RAW_HARDWARE; } if (setsockopt(handle->fd, SOL_PACKET, PACKET_TIMESTAMP, (void *)×ource, sizeof(timesource))) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't set PACKET_TIMESTAMP: %s", pcap_strerror(errno)); *status = PCAP_ERROR; return -1; } } } #endif /* HAVE_LINUX_NET_TSTAMP_H && PACKET_TIMESTAMP */ /* ask the kernel to create the ring */ retry: req.tp_block_nr = req.tp_frame_nr / frames_per_block; /* req.tp_frame_nr is requested to match frames_per_block*req.tp_block_nr */ req.tp_frame_nr = req.tp_block_nr * frames_per_block; #ifdef HAVE_TPACKET3 /* timeout value to retire block - use the configured buffering timeout, or default if <0. */ req.tp_retire_blk_tov = (handlep->timeout>=0)?handlep->timeout:0; /* private data not used */ req.tp_sizeof_priv = 0; /* Rx ring - feature request bits - none (rxhash will not be filled) */ req.tp_feature_req_word = 0; #endif if (setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING, (void *) &req, sizeof(req))) { if ((errno == ENOMEM) && (req.tp_block_nr > 1)) { /* * Memory failure; try to reduce the requested ring * size. * * We used to reduce this by half -- do 5% instead. * That may result in more iterations and a longer * startup, but the user will be much happier with * the resulting buffer size. */ if (req.tp_frame_nr < 20) req.tp_frame_nr -= 1; else req.tp_frame_nr -= req.tp_frame_nr/20; goto retry; } if (errno == ENOPROTOOPT) { /* * We don't have ring buffer support in this kernel. */ return 0; } pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't create rx ring on packet socket: %s", pcap_strerror(errno)); *status = PCAP_ERROR; return -1; } /* memory map the rx ring */ handlep->mmapbuflen = req.tp_block_nr * req.tp_block_size; handlep->mmapbuf = mmap(0, handlep->mmapbuflen, PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0); if (handlep->mmapbuf == MAP_FAILED) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't mmap rx ring: %s", pcap_strerror(errno)); /* clear the allocated ring on error*/ destroy_ring(handle); *status = PCAP_ERROR; return -1; } /* allocate a ring for each frame header pointer*/ handle->cc = req.tp_frame_nr; handle->buffer = malloc(handle->cc * sizeof(union thdr *)); if (!handle->buffer) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't allocate ring of frame headers: %s", pcap_strerror(errno)); destroy_ring(handle); *status = PCAP_ERROR; return -1; } /* fill the header ring with proper frame ptr*/ handle->offset = 0; for (i=0; immapbuf[i*req.tp_block_size]; for (j=0; joffset) { RING_GET_CURRENT_FRAME(handle) = base; base += req.tp_frame_size; } } handle->bufsize = req.tp_frame_size; handle->offset = 0; return 1; } /* free all ring related resources*/ static void destroy_ring(pcap_t *handle) { struct pcap_linux *handlep = handle->priv; /* tell the kernel to destroy the ring*/ struct tpacket_req req; memset(&req, 0, sizeof(req)); /* do not test for setsockopt failure, as we can't recover from any error */ (void)setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING, (void *) &req, sizeof(req)); /* if ring is mapped, unmap it*/ if (handlep->mmapbuf) { /* do not test for mmap failure, as we can't recover from any error */ (void)munmap(handlep->mmapbuf, handlep->mmapbuflen); handlep->mmapbuf = NULL; } } /* * Special one-shot callback, used for pcap_next() and pcap_next_ex(), * for Linux mmapped capture. * * The problem is that pcap_next() and pcap_next_ex() expect the packet * data handed to the callback to be valid after the callback returns, * but pcap_read_linux_mmap() has to release that packet as soon as * the callback returns (otherwise, the kernel thinks there's still * at least one unprocessed packet available in the ring, so a select() * will immediately return indicating that there's data to process), so, * in the callback, we have to make a copy of the packet. * * Yes, this means that, if the capture is using the ring buffer, using * pcap_next() or pcap_next_ex() requires more copies than using * pcap_loop() or pcap_dispatch(). If that bothers you, don't use * pcap_next() or pcap_next_ex(). */ static void pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) { struct oneshot_userdata *sp = (struct oneshot_userdata *)user; pcap_t *handle = sp->pd; struct pcap_linux *handlep = handle->priv; *sp->hdr = *h; memcpy(handlep->oneshot_buffer, bytes, h->caplen); *sp->pkt = handlep->oneshot_buffer; } static void pcap_cleanup_linux_mmap( pcap_t *handle ) { struct pcap_linux *handlep = handle->priv; destroy_ring(handle); if (handlep->oneshot_buffer != NULL) { free(handlep->oneshot_buffer); handlep->oneshot_buffer = NULL; } pcap_cleanup_linux(handle); } static int pcap_getnonblock_mmap(pcap_t *p, char *errbuf) { struct pcap_linux *handlep = p->priv; /* use negative value of timeout to indicate non blocking ops */ return (handlep->timeout<0); } static int pcap_setnonblock_mmap(pcap_t *p, int nonblock, char *errbuf) { struct pcap_linux *handlep = p->priv; /* * Set the file descriptor to non-blocking mode, as we use * it for sending packets. */ if (pcap_setnonblock_fd(p, nonblock, errbuf) == -1) return -1; /* * Map each value to their corresponding negation to * preserve the timeout value provided with pcap_set_timeout. */ if (nonblock) { if (handlep->timeout >= 0) { /* * Indicate that we're switching to * non-blocking mode. */ handlep->timeout = ~handlep->timeout; } } else { if (handlep->timeout < 0) { handlep->timeout = ~handlep->timeout; } } /* Update the timeout to use in poll(). */ set_poll_timeout(handlep); return 0; } /* * Get the status field of the ring buffer frame at a specified offset. */ static inline int pcap_get_ring_frame_status(pcap_t *handle, int offset) { struct pcap_linux *handlep = handle->priv; union thdr h; h.raw = RING_GET_FRAME_AT(handle, offset); switch (handlep->tp_version) { case TPACKET_V1: return (h.h1->tp_status); break; case TPACKET_V1_64: return (h.h1_64->tp_status); break; #ifdef HAVE_TPACKET2 case TPACKET_V2: return (h.h2->tp_status); break; #endif #ifdef HAVE_TPACKET3 case TPACKET_V3: return (h.h3->hdr.bh1.block_status); break; #endif } /* This should not happen. */ return 0; } #ifndef POLLRDHUP #define POLLRDHUP 0 #endif /* * Block waiting for frames to be available. */ static int pcap_wait_for_frames_mmap(pcap_t *handle) { struct pcap_linux *handlep = handle->priv; char c; struct pollfd pollinfo; int ret; pollinfo.fd = handle->fd; pollinfo.events = POLLIN; do { /* * Yes, we do this even in non-blocking mode, as it's * the only way to get error indications from a * tpacket socket. * * The timeout is 0 in non-blocking mode, so poll() * returns immediately. */ ret = poll(&pollinfo, 1, handlep->poll_timeout); if (ret < 0 && errno != EINTR) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't poll on packet socket: %s", pcap_strerror(errno)); return PCAP_ERROR; } else if (ret > 0 && (pollinfo.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) { /* * There's some indication other than * "you can read on this descriptor" on * the descriptor. */ if (pollinfo.revents & (POLLHUP | POLLRDHUP)) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Hangup on packet socket"); return PCAP_ERROR; } if (pollinfo.revents & POLLERR) { /* * A recv() will give us the actual error code. * * XXX - make the socket non-blocking? */ if (recv(handle->fd, &c, sizeof c, MSG_PEEK) != -1) continue; /* what, no error? */ if (errno == ENETDOWN) { /* * The device on which we're * capturing went away. * * XXX - we should really return * PCAP_ERROR_IFACE_NOT_UP, but * pcap_dispatch() etc. aren't * defined to return that. */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "The interface went down"); } else { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Error condition on packet socket: %s", strerror(errno)); } return PCAP_ERROR; } if (pollinfo.revents & POLLNVAL) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Invalid polling request on packet socket"); return PCAP_ERROR; } } /* check for break loop condition on interrupted syscall*/ if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } } while (ret < 0); return 0; } /* handle a single memory mapped packet */ static int pcap_handle_packet_mmap( pcap_t *handle, pcap_handler callback, u_char *user, unsigned char *frame, unsigned int tp_len, unsigned int tp_mac, unsigned int tp_snaplen, unsigned int tp_sec, unsigned int tp_usec, int tp_vlan_tci_valid, __u16 tp_vlan_tci, __u16 tp_vlan_tpid) { struct pcap_linux *handlep = handle->priv; unsigned char *bp; struct sockaddr_ll *sll; struct pcap_pkthdr pcaphdr; /* perform sanity check on internal offset. */ if (tp_mac + tp_snaplen > handle->bufsize) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "corrupted frame on kernel ring mac " "offset %u + caplen %u > frame len %d", tp_mac, tp_snaplen, handle->bufsize); return -1; } /* run filter on received packet * If the kernel filtering is enabled we need to run the * filter until all the frames present into the ring * at filter creation time are processed. * In this case, blocks_to_filter_in_userland is used * as a counter for the packet we need to filter. * Note: alternatively it could be possible to stop applying * the filter when the ring became empty, but it can possibly * happen a lot later... */ bp = frame + tp_mac; /* if required build in place the sll header*/ sll = (void *)frame + TPACKET_ALIGN(handlep->tp_hdrlen); if (handlep->cooked) { struct sll_header *hdrp; /* * The kernel should have left us with enough * space for an sll header; back up the packet * data pointer into that space, as that'll be * the beginning of the packet we pass to the * callback. */ bp -= SLL_HDR_LEN; /* * Let's make sure that's past the end of * the tpacket header, i.e. >= * ((u_char *)thdr + TPACKET_HDRLEN), so we * don't step on the header when we construct * the sll header. */ if (bp < (u_char *)frame + TPACKET_ALIGN(handlep->tp_hdrlen) + sizeof(struct sockaddr_ll)) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "cooked-mode frame doesn't have room for sll header"); return -1; } /* * OK, that worked; construct the sll header. */ hdrp = (struct sll_header *)bp; hdrp->sll_pkttype = map_packet_type_to_sll_type( sll->sll_pkttype); hdrp->sll_hatype = htons(sll->sll_hatype); hdrp->sll_halen = htons(sll->sll_halen); memcpy(hdrp->sll_addr, sll->sll_addr, SLL_ADDRLEN); hdrp->sll_protocol = sll->sll_protocol; } if (handlep->filter_in_userland && handle->fcode.bf_insns) { struct bpf_aux_data aux_data; aux_data.vlan_tag = tp_vlan_tci & 0x0fff; aux_data.vlan_tag_present = tp_vlan_tci_valid; if (bpf_filter_with_aux_data(handle->fcode.bf_insns, bp, tp_len, tp_snaplen, &aux_data) == 0) return 0; } if (!linux_check_direction(handle, sll)) return 0; /* get required packet info from ring header */ pcaphdr.ts.tv_sec = tp_sec; pcaphdr.ts.tv_usec = tp_usec; pcaphdr.caplen = tp_snaplen; pcaphdr.len = tp_len; /* if required build in place the sll header*/ if (handlep->cooked) { /* update packet len */ pcaphdr.caplen += SLL_HDR_LEN; pcaphdr.len += SLL_HDR_LEN; } #if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3) if (tp_vlan_tci_valid && handlep->vlan_offset != -1 && tp_snaplen >= (unsigned int) handlep->vlan_offset) { struct vlan_tag *tag; /* * Move everything in the header, except the type field, * down VLAN_TAG_LEN bytes, to allow us to insert the * VLAN tag between that stuff and the type field. */ bp -= VLAN_TAG_LEN; memmove(bp, bp + VLAN_TAG_LEN, handlep->vlan_offset); /* * Now insert the tag. */ tag = (struct vlan_tag *)(bp + handlep->vlan_offset); tag->vlan_tpid = htons(tp_vlan_tpid); tag->vlan_tci = htons(tp_vlan_tci); /* * Add the tag to the packet lengths. */ pcaphdr.caplen += VLAN_TAG_LEN; pcaphdr.len += VLAN_TAG_LEN; } #endif /* * The only way to tell the kernel to cut off the * packet at a snapshot length is with a filter program; * if there's no filter program, the kernel won't cut * the packet off. * * Trim the snapshot length to be no longer than the * specified snapshot length. */ if (pcaphdr.caplen > (bpf_u_int32)handle->snapshot) pcaphdr.caplen = handle->snapshot; /* pass the packet to the user */ callback(user, &pcaphdr, bp); return 1; } static int pcap_read_linux_mmap_v1(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_linux *handlep = handle->priv; union thdr h; int pkts = 0; int ret; /* wait for frames availability.*/ h.raw = RING_GET_CURRENT_FRAME(handle); if (h.h1->tp_status == TP_STATUS_KERNEL) { /* * The current frame is owned by the kernel; wait for * a frame to be handed to us. */ ret = pcap_wait_for_frames_mmap(handle); if (ret) { return ret; } } /* non-positive values of max_packets are used to require all * packets currently available in the ring */ while ((pkts < max_packets) || PACKET_COUNT_IS_UNLIMITED(max_packets)) { /* * Get the current ring buffer frame, and break if * it's still owned by the kernel. */ h.raw = RING_GET_CURRENT_FRAME(handle); if (h.h1->tp_status == TP_STATUS_KERNEL) break; ret = pcap_handle_packet_mmap( handle, callback, user, h.raw, h.h1->tp_len, h.h1->tp_mac, h.h1->tp_snaplen, h.h1->tp_sec, h.h1->tp_usec, 0, 0, 0); if (ret == 1) { pkts++; handlep->packets_read++; } else if (ret < 0) { return ret; } /* * Hand this block back to the kernel, and, if we're * counting blocks that need to be filtered in userland * after having been filtered by the kernel, count * the one we've just processed. */ h.h1->tp_status = TP_STATUS_KERNEL; if (handlep->blocks_to_filter_in_userland > 0) { handlep->blocks_to_filter_in_userland--; if (handlep->blocks_to_filter_in_userland == 0) { /* * No more blocks need to be filtered * in userland. */ handlep->filter_in_userland = 0; } } /* next block */ if (++handle->offset >= handle->cc) handle->offset = 0; /* check for break loop condition*/ if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } } return pkts; } static int pcap_read_linux_mmap_v1_64(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_linux *handlep = handle->priv; union thdr h; int pkts = 0; int ret; /* wait for frames availability.*/ h.raw = RING_GET_CURRENT_FRAME(handle); if (h.h1_64->tp_status == TP_STATUS_KERNEL) { /* * The current frame is owned by the kernel; wait for * a frame to be handed to us. */ ret = pcap_wait_for_frames_mmap(handle); if (ret) { return ret; } } /* non-positive values of max_packets are used to require all * packets currently available in the ring */ while ((pkts < max_packets) || PACKET_COUNT_IS_UNLIMITED(max_packets)) { /* * Get the current ring buffer frame, and break if * it's still owned by the kernel. */ h.raw = RING_GET_CURRENT_FRAME(handle); if (h.h1_64->tp_status == TP_STATUS_KERNEL) break; ret = pcap_handle_packet_mmap( handle, callback, user, h.raw, h.h1_64->tp_len, h.h1_64->tp_mac, h.h1_64->tp_snaplen, h.h1_64->tp_sec, h.h1_64->tp_usec, 0, 0, 0); if (ret == 1) { pkts++; handlep->packets_read++; } else if (ret < 0) { return ret; } /* * Hand this block back to the kernel, and, if we're * counting blocks that need to be filtered in userland * after having been filtered by the kernel, count * the one we've just processed. */ h.h1_64->tp_status = TP_STATUS_KERNEL; if (handlep->blocks_to_filter_in_userland > 0) { handlep->blocks_to_filter_in_userland--; if (handlep->blocks_to_filter_in_userland == 0) { /* * No more blocks need to be filtered * in userland. */ handlep->filter_in_userland = 0; } } /* next block */ if (++handle->offset >= handle->cc) handle->offset = 0; /* check for break loop condition*/ if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } } return pkts; } #ifdef HAVE_TPACKET2 static int pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_linux *handlep = handle->priv; union thdr h; int pkts = 0; int ret; /* wait for frames availability.*/ h.raw = RING_GET_CURRENT_FRAME(handle); if (h.h2->tp_status == TP_STATUS_KERNEL) { /* * The current frame is owned by the kernel; wait for * a frame to be handed to us. */ ret = pcap_wait_for_frames_mmap(handle); if (ret) { return ret; } } /* non-positive values of max_packets are used to require all * packets currently available in the ring */ while ((pkts < max_packets) || PACKET_COUNT_IS_UNLIMITED(max_packets)) { /* * Get the current ring buffer frame, and break if * it's still owned by the kernel. */ h.raw = RING_GET_CURRENT_FRAME(handle); if (h.h2->tp_status == TP_STATUS_KERNEL) break; ret = pcap_handle_packet_mmap( handle, callback, user, h.raw, h.h2->tp_len, h.h2->tp_mac, h.h2->tp_snaplen, h.h2->tp_sec, handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? h.h2->tp_nsec : h.h2->tp_nsec / 1000, #if defined(TP_STATUS_VLAN_VALID) (h.h2->tp_vlan_tci || (h.h2->tp_status & TP_STATUS_VLAN_VALID)), #else h.h2->tp_vlan_tci != 0, #endif h.h2->tp_vlan_tci, VLAN_TPID(h.h2, h.h2)); if (ret == 1) { pkts++; handlep->packets_read++; } else if (ret < 0) { return ret; } /* * Hand this block back to the kernel, and, if we're * counting blocks that need to be filtered in userland * after having been filtered by the kernel, count * the one we've just processed. */ h.h2->tp_status = TP_STATUS_KERNEL; if (handlep->blocks_to_filter_in_userland > 0) { handlep->blocks_to_filter_in_userland--; if (handlep->blocks_to_filter_in_userland == 0) { /* * No more blocks need to be filtered * in userland. */ handlep->filter_in_userland = 0; } } /* next block */ if (++handle->offset >= handle->cc) handle->offset = 0; /* check for break loop condition*/ if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } } return pkts; } #endif /* HAVE_TPACKET2 */ #ifdef HAVE_TPACKET3 static int pcap_read_linux_mmap_v3(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_linux *handlep = handle->priv; union thdr h; int pkts = 0; int ret; again: if (handlep->current_packet == NULL) { /* wait for frames availability.*/ h.raw = RING_GET_CURRENT_FRAME(handle); if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL) { /* * The current frame is owned by the kernel; wait * for a frame to be handed to us. */ ret = pcap_wait_for_frames_mmap(handle); if (ret) { return ret; } } } h.raw = RING_GET_CURRENT_FRAME(handle); if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL) { if (pkts == 0 && handlep->timeout == 0) { /* Block until we see a packet. */ goto again; } return pkts; } /* non-positive values of max_packets are used to require all * packets currently available in the ring */ while ((pkts < max_packets) || PACKET_COUNT_IS_UNLIMITED(max_packets)) { int packets_to_read; if (handlep->current_packet == NULL) { h.raw = RING_GET_CURRENT_FRAME(handle); if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL) break; handlep->current_packet = h.raw + h.h3->hdr.bh1.offset_to_first_pkt; handlep->packets_left = h.h3->hdr.bh1.num_pkts; } packets_to_read = handlep->packets_left; if (!PACKET_COUNT_IS_UNLIMITED(max_packets) && packets_to_read > (max_packets - pkts)) { /* * We've been given a maximum number of packets * to process, and there are more packets in * this buffer than that. Only process enough * of them to get us up to that maximum. */ packets_to_read = max_packets - pkts; } while (packets_to_read-- && !handle->break_loop) { struct tpacket3_hdr* tp3_hdr = (struct tpacket3_hdr*) handlep->current_packet; ret = pcap_handle_packet_mmap( handle, callback, user, handlep->current_packet, tp3_hdr->tp_len, tp3_hdr->tp_mac, tp3_hdr->tp_snaplen, tp3_hdr->tp_sec, handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? tp3_hdr->tp_nsec : tp3_hdr->tp_nsec / 1000, #if defined(TP_STATUS_VLAN_VALID) (tp3_hdr->hv1.tp_vlan_tci || (tp3_hdr->tp_status & TP_STATUS_VLAN_VALID)), #else tp3_hdr->hv1.tp_vlan_tci != 0, #endif tp3_hdr->hv1.tp_vlan_tci, VLAN_TPID(tp3_hdr, &tp3_hdr->hv1)); if (ret == 1) { pkts++; handlep->packets_read++; } else if (ret < 0) { handlep->current_packet = NULL; return ret; } handlep->current_packet += tp3_hdr->tp_next_offset; handlep->packets_left--; } if (handlep->packets_left <= 0) { /* * Hand this block back to the kernel, and, if * we're counting blocks that need to be * filtered in userland after having been * filtered by the kernel, count the one we've * just processed. */ h.h3->hdr.bh1.block_status = TP_STATUS_KERNEL; if (handlep->blocks_to_filter_in_userland > 0) { handlep->blocks_to_filter_in_userland--; if (handlep->blocks_to_filter_in_userland == 0) { /* * No more blocks need to be filtered * in userland. */ handlep->filter_in_userland = 0; } } /* next block */ if (++handle->offset >= handle->cc) handle->offset = 0; handlep->current_packet = NULL; } /* check for break loop condition*/ if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } } if (pkts == 0 && handlep->timeout == 0) { /* Block until we see a packet. */ goto again; } return pkts; } #endif /* HAVE_TPACKET3 */ static int pcap_setfilter_linux_mmap(pcap_t *handle, struct bpf_program *filter) { struct pcap_linux *handlep = handle->priv; int n, offset; int ret; /* * Don't rewrite "ret" instructions; we don't need to, as * we're not reading packets with recvmsg(), and we don't * want to, as, by not rewriting them, the kernel can avoid * copying extra data. */ ret = pcap_setfilter_linux_common(handle, filter, 1); if (ret < 0) return ret; /* * If we're filtering in userland, there's nothing to do; * the new filter will be used for the next packet. */ if (handlep->filter_in_userland) return ret; /* * We're filtering in the kernel; the packets present in * all blocks currently in the ring were already filtered * by the old filter, and so will need to be filtered in * userland by the new filter. * * Get an upper bound for the number of such blocks; first, * walk the ring backward and count the free blocks. */ offset = handle->offset; if (--offset < 0) offset = handle->cc - 1; for (n=0; n < handle->cc; ++n) { if (--offset < 0) offset = handle->cc - 1; if (pcap_get_ring_frame_status(handle, offset) != TP_STATUS_KERNEL) break; } /* * If we found free blocks, decrement the count of free * blocks by 1, just in case we lost a race with another * thread of control that was adding a packet while * we were counting and that had run the filter before * we changed it. * * XXX - could there be more than one block added in * this fashion? * * XXX - is there a way to avoid that race, e.g. somehow * wait for all packets that passed the old filter to * be added to the ring? */ if (n != 0) n--; /* * Set the count of blocks worth of packets to filter * in userland to the total number of blocks in the * ring minus the number of free blocks we found, and * turn on userland filtering. (The count of blocks * worth of packets to filter in userland is guaranteed * not to be zero - n, above, couldn't be set to a * value > handle->cc, and if it were equal to * handle->cc, it wouldn't be zero, and thus would * be decremented to handle->cc - 1.) */ handlep->blocks_to_filter_in_userland = handle->cc - n; handlep->filter_in_userland = 1; return ret; } #endif /* HAVE_PACKET_RING */ #ifdef HAVE_PF_PACKET_SOCKETS /* * Return the index of the given device name. Fill ebuf and return * -1 on failure. */ static int iface_get_id(int fd, const char *device, char *ebuf) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCGIFINDEX: %s", pcap_strerror(errno)); return -1; } return ifr.ifr_ifindex; } /* * Bind the socket associated with FD to the given device. * Return 1 on success, 0 if we should try a SOCK_PACKET socket, * or a PCAP_ERROR_ value on a hard error. */ static int iface_bind(int fd, int ifindex, char *ebuf) { struct sockaddr_ll sll; int err; socklen_t errlen = sizeof(err); memset(&sll, 0, sizeof(sll)); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifindex; sll.sll_protocol = htons(ETH_P_ALL); if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1) { if (errno == ENETDOWN) { /* * Return a "network down" indication, so that * the application can report that rather than * saying we had a mysterious failure and * suggest that they report a problem to the * libpcap developers. */ return PCAP_ERROR_IFACE_NOT_UP; } else { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "bind: %s", pcap_strerror(errno)); return PCAP_ERROR; } } /* Any pending errors, e.g., network is down? */ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "getsockopt: %s", pcap_strerror(errno)); return 0; } if (err == ENETDOWN) { /* * Return a "network down" indication, so that * the application can report that rather than * saying we had a mysterious failure and * suggest that they report a problem to the * libpcap developers. */ return PCAP_ERROR_IFACE_NOT_UP; } else if (err > 0) { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "bind: %s", pcap_strerror(err)); return 0; } return 1; } #ifdef IW_MODE_MONITOR /* * Check whether the device supports the Wireless Extensions. * Returns 1 if it does, 0 if it doesn't, PCAP_ERROR_NO_SUCH_DEVICE * if the device doesn't even exist. */ static int has_wext(int sock_fd, const char *device, char *ebuf) { struct iwreq ireq; if (is_bonding_device(sock_fd, device)) return 0; /* bonding device, so don't even try */ strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); if (ioctl(sock_fd, SIOCGIWNAME, &ireq) >= 0) return 1; /* yes */ pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: SIOCGIWNAME: %s", device, pcap_strerror(errno)); if (errno == ENODEV) return PCAP_ERROR_NO_SUCH_DEVICE; return 0; } /* * Per me si va ne la citta dolente, * Per me si va ne l'etterno dolore, * ... * Lasciate ogne speranza, voi ch'intrate. * * XXX - airmon-ng does special stuff with the Orinoco driver and the * wlan-ng driver. */ typedef enum { MONITOR_WEXT, MONITOR_HOSTAP, MONITOR_PRISM, MONITOR_PRISM54, MONITOR_ACX100, MONITOR_RT2500, MONITOR_RT2570, MONITOR_RT73, MONITOR_RTL8XXX } monitor_type; /* * Use the Wireless Extensions, if we have them, to try to turn monitor mode * on if it's not already on. * * Returns 1 on success, 0 if we don't support the Wireless Extensions * on this device, or a PCAP_ERROR_ value if we do support them but * we weren't able to turn monitor mode on. */ static int enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) { /* * XXX - at least some adapters require non-Wireless Extensions * mechanisms to turn monitor mode on. * * Atheros cards might require that a separate "monitor virtual access * point" be created, with later versions of the madwifi driver. * airmon-ng does "wlanconfig ath create wlandev {if} wlanmode * monitor -bssid", which apparently spits out a line "athN" * where "athN" is the monitor mode device. To leave monitor * mode, it destroys the monitor mode device. * * Some Intel Centrino adapters might require private ioctls to get * radio headers; the ipw2200 and ipw3945 drivers allow you to * configure a separate "rtapN" interface to capture in monitor * mode without preventing the adapter from operating normally. * (airmon-ng doesn't appear to use that, though.) * * It would be Truly Wonderful if mac80211 and nl80211 cleaned this * up, and if all drivers were converted to mac80211 drivers. * * If interface {if} is a mac80211 driver, the file * /sys/class/net/{if}/phy80211 is a symlink to * /sys/class/ieee80211/{phydev}, for some {phydev}. * * On Fedora 9, with a 2.6.26.3-29 kernel, my Zydas stick, at * least, has a "wmaster0" device and a "wlan0" device; the * latter is the one with the IP address. Both show up in * "tcpdump -D" output. Capturing on the wmaster0 device * captures with 802.11 headers. * * airmon-ng searches through /sys/class/net for devices named * monN, starting with mon0; as soon as one *doesn't* exist, * it chooses that as the monitor device name. If the "iw" * command exists, it does "iw dev {if} interface add {monif} * type monitor", where {monif} is the monitor device. It * then (sigh) sleeps .1 second, and then configures the * device up. Otherwise, if /sys/class/ieee80211/{phydev}/add_iface * is a file, it writes {mondev}, without a newline, to that file, * and again (sigh) sleeps .1 second, and then iwconfig's that * device into monitor mode and configures it up. Otherwise, * you can't do monitor mode. * * All these devices are "glued" together by having the * /sys/class/net/{device}/phy80211 links pointing to the same * place, so, given a wmaster, wlan, or mon device, you can * find the other devices by looking for devices with * the same phy80211 link. * * To turn monitor mode off, delete the monitor interface, * either with "iw dev {monif} interface del" or by sending * {monif}, with no NL, down /sys/class/ieee80211/{phydev}/remove_iface * * Note: if you try to create a monitor device named "monN", and * there's already a "monN" device, it fails, as least with * the netlink interface (which is what iw uses), with a return * value of -ENFILE. (Return values are negative errnos.) We * could probably use that to find an unused device. */ struct pcap_linux *handlep = handle->priv; int err; struct iwreq ireq; struct iw_priv_args *priv; monitor_type montype; int i; __u32 cmd; struct ifreq ifr; int oldflags; int args[2]; int channel; /* * Does this device *support* the Wireless Extensions? */ err = has_wext(sock_fd, device, handle->errbuf); if (err <= 0) return err; /* either it doesn't or the device doesn't even exist */ /* * Start out assuming we have no private extensions to control * radio metadata. */ montype = MONITOR_WEXT; cmd = 0; /* * Try to get all the Wireless Extensions private ioctls * supported by this device. * * First, get the size of the buffer we need, by supplying no * buffer and a length of 0. If the device supports private * ioctls, it should return E2BIG, with ireq.u.data.length set * to the length we need. If it doesn't support them, it should * return EOPNOTSUPP. */ memset(&ireq, 0, sizeof ireq); strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); ireq.u.data.pointer = (void *)args; ireq.u.data.length = 0; ireq.u.data.flags = 0; if (ioctl(sock_fd, SIOCGIWPRIV, &ireq) != -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: SIOCGIWPRIV with a zero-length buffer didn't fail!", device); return PCAP_ERROR; } if (errno != EOPNOTSUPP) { /* * OK, it's not as if there are no private ioctls. */ if (errno != E2BIG) { /* * Failed. */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: SIOCGIWPRIV: %s", device, pcap_strerror(errno)); return PCAP_ERROR; } /* * OK, try to get the list of private ioctls. */ priv = malloc(ireq.u.data.length * sizeof (struct iw_priv_args)); if (priv == NULL) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return PCAP_ERROR; } ireq.u.data.pointer = (void *)priv; if (ioctl(sock_fd, SIOCGIWPRIV, &ireq) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: SIOCGIWPRIV: %s", device, pcap_strerror(errno)); free(priv); return PCAP_ERROR; } /* * Look for private ioctls to turn monitor mode on or, if * monitor mode is on, to set the header type. */ for (i = 0; i < ireq.u.data.length; i++) { if (strcmp(priv[i].name, "monitor_type") == 0) { /* * Hostap driver, use this one. * Set monitor mode first. * You can set it to 0 to get DLT_IEEE80211, * 1 to get DLT_PRISM, 2 to get * DLT_IEEE80211_RADIO_AVS, and, with more * recent versions of the driver, 3 to get * DLT_IEEE80211_RADIO. */ if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) break; if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED)) break; if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1) break; montype = MONITOR_HOSTAP; cmd = priv[i].cmd; break; } if (strcmp(priv[i].name, "set_prismhdr") == 0) { /* * Prism54 driver, use this one. * Set monitor mode first. * You can set it to 2 to get DLT_IEEE80211 * or 3 or get DLT_PRISM. */ if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) break; if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED)) break; if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1) break; montype = MONITOR_PRISM54; cmd = priv[i].cmd; break; } if (strcmp(priv[i].name, "forceprismheader") == 0) { /* * RT2570 driver, use this one. * Do this after turning monitor mode on. * You can set it to 1 to get DLT_PRISM or 2 * to get DLT_IEEE80211. */ if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) break; if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED)) break; if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1) break; montype = MONITOR_RT2570; cmd = priv[i].cmd; break; } if (strcmp(priv[i].name, "forceprism") == 0) { /* * RT73 driver, use this one. * Do this after turning monitor mode on. * Its argument is a *string*; you can * set it to "1" to get DLT_PRISM or "2" * to get DLT_IEEE80211. */ if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_CHAR) break; if (priv[i].set_args & IW_PRIV_SIZE_FIXED) break; montype = MONITOR_RT73; cmd = priv[i].cmd; break; } if (strcmp(priv[i].name, "prismhdr") == 0) { /* * One of the RTL8xxx drivers, use this one. * It can only be done after monitor mode * has been turned on. You can set it to 1 * to get DLT_PRISM or 0 to get DLT_IEEE80211. */ if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) break; if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED)) break; if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1) break; montype = MONITOR_RTL8XXX; cmd = priv[i].cmd; break; } if (strcmp(priv[i].name, "rfmontx") == 0) { /* * RT2500 or RT61 driver, use this one. * It has one one-byte parameter; set * u.data.length to 1 and u.data.pointer to * point to the parameter. * It doesn't itself turn monitor mode on. * You can set it to 1 to allow transmitting * in monitor mode(?) and get DLT_IEEE80211, * or set it to 0 to disallow transmitting in * monitor mode(?) and get DLT_PRISM. */ if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) break; if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 2) break; montype = MONITOR_RT2500; cmd = priv[i].cmd; break; } if (strcmp(priv[i].name, "monitor") == 0) { /* * Either ACX100 or hostap, use this one. * It turns monitor mode on. * If it takes two arguments, it's ACX100; * the first argument is 1 for DLT_PRISM * or 2 for DLT_IEEE80211, and the second * argument is the channel on which to * run. If it takes one argument, it's * HostAP, and the argument is 2 for * DLT_IEEE80211 and 3 for DLT_PRISM. * * If we see this, we don't quit, as this * might be a version of the hostap driver * that also supports "monitor_type". */ if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) break; if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED)) break; switch (priv[i].set_args & IW_PRIV_SIZE_MASK) { case 1: montype = MONITOR_PRISM; cmd = priv[i].cmd; break; case 2: montype = MONITOR_ACX100; cmd = priv[i].cmd; break; default: break; } } } free(priv); } /* * XXX - ipw3945? islism? */ /* * Get the old mode. */ strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); if (ioctl(sock_fd, SIOCGIWMODE, &ireq) == -1) { /* * We probably won't be able to set the mode, either. */ return PCAP_ERROR_RFMON_NOTSUP; } /* * Is it currently in monitor mode? */ if (ireq.u.mode == IW_MODE_MONITOR) { /* * Yes. Just leave things as they are. * We don't offer multiple link-layer types, as * changing the link-layer type out from under * somebody else capturing in monitor mode would * be considered rude. */ return 1; } /* * No. We have to put the adapter into rfmon mode. */ /* * If we haven't already done so, arrange to have * "pcap_close_all()" called when we exit. */ if (!pcap_do_addexit(handle)) { /* * "atexit()" failed; don't put the interface * in rfmon mode, just give up. */ return PCAP_ERROR_RFMON_NOTSUP; } /* * Save the old mode. */ handlep->oldmode = ireq.u.mode; /* * Put the adapter in rfmon mode. How we do this depends * on whether we have a special private ioctl or not. */ if (montype == MONITOR_PRISM) { /* * We have the "monitor" private ioctl, but none of * the other private ioctls. Use this, and select * the Prism header. * * If it fails, just fall back on SIOCSIWMODE. */ memset(&ireq, 0, sizeof ireq); strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); ireq.u.data.length = 1; /* 1 argument */ args[0] = 3; /* request Prism header */ memcpy(ireq.u.name, args, sizeof (int)); if (ioctl(sock_fd, cmd, &ireq) != -1) { /* * Success. * Note that we have to put the old mode back * when we close the device. */ handlep->must_do_on_close |= MUST_CLEAR_RFMON; /* * Add this to the list of pcaps to close * when we exit. */ pcap_add_to_pcaps_to_close(handle); return 1; } /* * Failure. Fall back on SIOCSIWMODE. */ } /* * First, take the interface down if it's up; otherwise, we * might get EBUSY. */ memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: Can't get flags: %s", device, strerror(errno)); return PCAP_ERROR; } oldflags = 0; if (ifr.ifr_flags & IFF_UP) { oldflags = ifr.ifr_flags; ifr.ifr_flags &= ~IFF_UP; if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: Can't set flags: %s", device, strerror(errno)); return PCAP_ERROR; } } /* * Then turn monitor mode on. */ strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); ireq.u.mode = IW_MODE_MONITOR; if (ioctl(sock_fd, SIOCSIWMODE, &ireq) == -1) { /* * Scientist, you've failed. * Bring the interface back up if we shut it down. */ ifr.ifr_flags = oldflags; if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: Can't set flags: %s", device, strerror(errno)); return PCAP_ERROR; } return PCAP_ERROR_RFMON_NOTSUP; } /* * XXX - airmon-ng does "iwconfig {if} key off" after setting * monitor mode and setting the channel, and then does * "iwconfig up". */ /* * Now select the appropriate radio header. */ switch (montype) { case MONITOR_WEXT: /* * We don't have any private ioctl to set the header. */ break; case MONITOR_HOSTAP: /* * Try to select the radiotap header. */ memset(&ireq, 0, sizeof ireq); strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 3; /* request radiotap header */ memcpy(ireq.u.name, args, sizeof (int)); if (ioctl(sock_fd, cmd, &ireq) != -1) break; /* success */ /* * That failed. Try to select the AVS header. */ memset(&ireq, 0, sizeof ireq); strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 2; /* request AVS header */ memcpy(ireq.u.name, args, sizeof (int)); if (ioctl(sock_fd, cmd, &ireq) != -1) break; /* success */ /* * That failed. Try to select the Prism header. */ memset(&ireq, 0, sizeof ireq); strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 1; /* request Prism header */ memcpy(ireq.u.name, args, sizeof (int)); ioctl(sock_fd, cmd, &ireq); break; case MONITOR_PRISM: /* * The private ioctl failed. */ break; case MONITOR_PRISM54: /* * Select the Prism header. */ memset(&ireq, 0, sizeof ireq); strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 3; /* request Prism header */ memcpy(ireq.u.name, args, sizeof (int)); ioctl(sock_fd, cmd, &ireq); break; case MONITOR_ACX100: /* * Get the current channel. */ memset(&ireq, 0, sizeof ireq); strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); if (ioctl(sock_fd, SIOCGIWFREQ, &ireq) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: SIOCGIWFREQ: %s", device, pcap_strerror(errno)); return PCAP_ERROR; } channel = ireq.u.freq.m; /* * Select the Prism header, and set the channel to the * current value. */ memset(&ireq, 0, sizeof ireq); strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 1; /* request Prism header */ args[1] = channel; /* set channel */ memcpy(ireq.u.name, args, 2*sizeof (int)); ioctl(sock_fd, cmd, &ireq); break; case MONITOR_RT2500: /* * Disallow transmission - that turns on the * Prism header. */ memset(&ireq, 0, sizeof ireq); strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 0; /* disallow transmitting */ memcpy(ireq.u.name, args, sizeof (int)); ioctl(sock_fd, cmd, &ireq); break; case MONITOR_RT2570: /* * Force the Prism header. */ memset(&ireq, 0, sizeof ireq); strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 1; /* request Prism header */ memcpy(ireq.u.name, args, sizeof (int)); ioctl(sock_fd, cmd, &ireq); break; case MONITOR_RT73: /* * Force the Prism header. */ memset(&ireq, 0, sizeof ireq); strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); ireq.u.data.length = 1; /* 1 argument */ ireq.u.data.pointer = "1"; ireq.u.data.flags = 0; ioctl(sock_fd, cmd, &ireq); break; case MONITOR_RTL8XXX: /* * Force the Prism header. */ memset(&ireq, 0, sizeof ireq); strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 1; /* request Prism header */ memcpy(ireq.u.name, args, sizeof (int)); ioctl(sock_fd, cmd, &ireq); break; } /* * Now bring the interface back up if we brought it down. */ if (oldflags != 0) { ifr.ifr_flags = oldflags; if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: Can't set flags: %s", device, strerror(errno)); /* * At least try to restore the old mode on the * interface. */ if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) { /* * Scientist, you've failed. */ fprintf(stderr, "Can't restore interface wireless mode (SIOCSIWMODE failed: %s).\n" "Please adjust manually.\n", strerror(errno)); } return PCAP_ERROR; } } /* * Note that we have to put the old mode back when we * close the device. */ handlep->must_do_on_close |= MUST_CLEAR_RFMON; /* * Add this to the list of pcaps to close when we exit. */ pcap_add_to_pcaps_to_close(handle); return 1; } #endif /* IW_MODE_MONITOR */ /* * Try various mechanisms to enter monitor mode. */ static int enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device) { #if defined(HAVE_LIBNL) || defined(IW_MODE_MONITOR) int ret; #endif #ifdef HAVE_LIBNL ret = enter_rfmon_mode_mac80211(handle, sock_fd, device); if (ret < 0) return ret; /* error attempting to do so */ if (ret == 1) return 1; /* success */ #endif /* HAVE_LIBNL */ #ifdef IW_MODE_MONITOR ret = enter_rfmon_mode_wext(handle, sock_fd, device); if (ret < 0) return ret; /* error attempting to do so */ if (ret == 1) return 1; /* success */ #endif /* IW_MODE_MONITOR */ /* * Either none of the mechanisms we know about work or none * of those mechanisms are available, so we can't do monitor * mode. */ return 0; } #if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) /* * Map SOF_TIMESTAMPING_ values to PCAP_TSTAMP_ values. */ static const struct { int soft_timestamping_val; int pcap_tstamp_val; } sof_ts_type_map[3] = { { SOF_TIMESTAMPING_SOFTWARE, PCAP_TSTAMP_HOST }, { SOF_TIMESTAMPING_SYS_HARDWARE, PCAP_TSTAMP_ADAPTER }, { SOF_TIMESTAMPING_RAW_HARDWARE, PCAP_TSTAMP_ADAPTER_UNSYNCED } }; #define NUM_SOF_TIMESTAMPING_TYPES (sizeof sof_ts_type_map / sizeof sof_ts_type_map[0]) /* * Set the list of time stamping types to include all types. */ static void iface_set_all_ts_types(pcap_t *handle) { u_int i; handle->tstamp_type_count = NUM_SOF_TIMESTAMPING_TYPES; handle->tstamp_type_list = malloc(NUM_SOF_TIMESTAMPING_TYPES * sizeof(u_int)); for (i = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) handle->tstamp_type_list[i] = sof_ts_type_map[i].pcap_tstamp_val; } #ifdef ETHTOOL_GET_TS_INFO /* * Get a list of time stamping capabilities. */ static int iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf) { int fd; struct ifreq ifr; struct ethtool_ts_info info; int num_ts_types; u_int i, j; /* * This doesn't apply to the "any" device; you can't say "turn on * hardware time stamping for all devices that exist now and arrange * that it be turned on for any device that appears in the future", * and not all devices even necessarily *support* hardware time * stamping, so don't report any time stamp types. */ if (strcmp(device, "any") == 0) { handle->tstamp_type_list = NULL; return 0; } /* * Create a socket from which to fetch time stamping capabilities. */ fd = socket(PF_UNIX, SOCK_RAW, 0); if (fd < 0) { (void)pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "socket for SIOCETHTOOL(ETHTOOL_GET_TS_INFO): %s", pcap_strerror(errno)); return -1; } memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); memset(&info, 0, sizeof(info)); info.cmd = ETHTOOL_GET_TS_INFO; ifr.ifr_data = (caddr_t)&info; if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) { int save_errno = errno; close(fd); switch (save_errno) { case EOPNOTSUPP: case EINVAL: /* * OK, this OS version or driver doesn't support * asking for the time stamping types, so let's * just return all the possible types. */ iface_set_all_ts_types(handle); return 0; case ENODEV: /* * OK, no such device. * The user will find that out when they try to * activate the device; just return an empty * list of time stamp types. */ handle->tstamp_type_list = NULL; return 0; default: /* * Other error. */ pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: SIOCETHTOOL(ETHTOOL_GET_TS_INFO) ioctl failed: %s", device, strerror(save_errno)); return -1; } } close(fd); /* * Do we support hardware time stamping of *all* packets? */ if (!(info.rx_filters & (1 << HWTSTAMP_FILTER_ALL))) { /* * No, so don't report any time stamp types. * * XXX - some devices either don't report * HWTSTAMP_FILTER_ALL when they do support it, or * report HWTSTAMP_FILTER_ALL but map it to only * time stamping a few PTP packets. See * http://marc.info/?l=linux-netdev&m=146318183529571&w=2 */ handle->tstamp_type_list = NULL; return 0; } num_ts_types = 0; for (i = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) { if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val) num_ts_types++; } handle->tstamp_type_count = num_ts_types; if (num_ts_types != 0) { handle->tstamp_type_list = malloc(num_ts_types * sizeof(u_int)); for (i = 0, j = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) { if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val) { handle->tstamp_type_list[j] = sof_ts_type_map[i].pcap_tstamp_val; j++; } } } else handle->tstamp_type_list = NULL; return 0; } #else /* ETHTOOL_GET_TS_INFO */ static int iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf _U_) { /* * This doesn't apply to the "any" device; you can't say "turn on * hardware time stamping for all devices that exist now and arrange * that it be turned on for any device that appears in the future", * and not all devices even necessarily *support* hardware time * stamping, so don't report any time stamp types. */ if (strcmp(device, "any") == 0) { handle->tstamp_type_list = NULL; return 0; } /* * We don't have an ioctl to use to ask what's supported, * so say we support everything. */ iface_set_all_ts_types(handle); return 0; } #endif /* ETHTOOL_GET_TS_INFO */ #endif /* defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) */ #ifdef HAVE_PACKET_RING /* * Find out if we have any form of fragmentation/reassembly offloading. * * We do so using SIOCETHTOOL checking for various types of offloading; * if SIOCETHTOOL isn't defined, or we don't have any #defines for any * of the types of offloading, there's nothing we can do to check, so * we just say "no, we don't". */ #if defined(SIOCETHTOOL) && (defined(ETHTOOL_GTSO) || defined(ETHTOOL_GUFO) || defined(ETHTOOL_GGSO) || defined(ETHTOOL_GFLAGS) || defined(ETHTOOL_GGRO)) static int iface_ethtool_flag_ioctl(pcap_t *handle, int cmd, const char *cmdname) { struct ifreq ifr; struct ethtool_value eval; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, handle->opt.device, sizeof(ifr.ifr_name)); eval.cmd = cmd; eval.data = 0; ifr.ifr_data = (caddr_t)&eval; if (ioctl(handle->fd, SIOCETHTOOL, &ifr) == -1) { if (errno == EOPNOTSUPP || errno == EINVAL) { /* * OK, let's just return 0, which, in our * case, either means "no, what we're asking * about is not enabled" or "all the flags * are clear (i.e., nothing is enabled)". */ return 0; } pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: SIOCETHTOOL(%s) ioctl failed: %s", handle->opt.device, cmdname, strerror(errno)); return -1; } return eval.data; } static int iface_get_offload(pcap_t *handle) { int ret; #ifdef ETHTOOL_GTSO ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GTSO, "ETHTOOL_GTSO"); if (ret == -1) return -1; if (ret) return 1; /* TCP segmentation offloading on */ #endif #ifdef ETHTOOL_GUFO ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GUFO, "ETHTOOL_GUFO"); if (ret == -1) return -1; if (ret) return 1; /* UDP fragmentation offloading on */ #endif #ifdef ETHTOOL_GGSO /* * XXX - will this cause large unsegmented packets to be * handed to PF_PACKET sockets on transmission? If not, * this need not be checked. */ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGSO, "ETHTOOL_GGSO"); if (ret == -1) return -1; if (ret) return 1; /* generic segmentation offloading on */ #endif #ifdef ETHTOOL_GFLAGS ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GFLAGS, "ETHTOOL_GFLAGS"); if (ret == -1) return -1; if (ret & ETH_FLAG_LRO) return 1; /* large receive offloading on */ #endif #ifdef ETHTOOL_GGRO /* * XXX - will this cause large reassembled packets to be * handed to PF_PACKET sockets on receipt? If not, * this need not be checked. */ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGRO, "ETHTOOL_GGRO"); if (ret == -1) return -1; if (ret) return 1; /* generic (large) receive offloading on */ #endif return 0; } #else /* SIOCETHTOOL */ static int iface_get_offload(pcap_t *handle _U_) { /* * XXX - do we need to get this information if we don't * have the ethtool ioctls? If so, how do we do that? */ return 0; } #endif /* SIOCETHTOOL */ #endif /* HAVE_PACKET_RING */ #endif /* HAVE_PF_PACKET_SOCKETS */ /* ===== Functions to interface to the older kernels ================== */ /* * Try to open a packet socket using the old kernel interface. * Returns 1 on success and a PCAP_ERROR_ value on an error. */ static int activate_old(pcap_t *handle) { struct pcap_linux *handlep = handle->priv; int arptype; struct ifreq ifr; const char *device = handle->opt.device; struct utsname utsname; int mtu; /* Open the socket */ handle->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL)); if (handle->fd == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); if (errno == EPERM || errno == EACCES) { /* * You don't have permission to open the * socket. */ return PCAP_ERROR_PERM_DENIED; } else { /* * Other error. */ return PCAP_ERROR; } } /* It worked - we are using the old interface */ handlep->sock_packet = 1; /* ...which means we get the link-layer header. */ handlep->cooked = 0; /* Bind to the given device */ if (strcmp(device, "any") == 0) { strlcpy(handle->errbuf, "pcap_activate: The \"any\" device isn't supported on 2.0[.x]-kernel systems", PCAP_ERRBUF_SIZE); return PCAP_ERROR; } if (iface_bind_old(handle->fd, device, handle->errbuf) == -1) return PCAP_ERROR; /* * Try to get the link-layer type. */ arptype = iface_get_arptype(handle->fd, device, handle->errbuf); if (arptype < 0) return PCAP_ERROR; /* * Try to find the DLT_ type corresponding to that * link-layer type. */ map_arphrd_to_dlt(handle, handle->fd, arptype, device, 0); if (handle->linktype == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "unknown arptype %d", arptype); return PCAP_ERROR; } /* Go to promisc mode if requested */ if (handle->opt.promisc) { memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFFLAGS: %s", pcap_strerror(errno)); return PCAP_ERROR; } if ((ifr.ifr_flags & IFF_PROMISC) == 0) { /* * Promiscuous mode isn't currently on, * so turn it on, and remember that * we should turn it off when the * pcap_t is closed. */ /* * If we haven't already done so, arrange * to have "pcap_close_all()" called when * we exit. */ if (!pcap_do_addexit(handle)) { /* * "atexit()" failed; don't put * the interface in promiscuous * mode, just give up. */ return PCAP_ERROR; } ifr.ifr_flags |= IFF_PROMISC; if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SIOCSIFFLAGS: %s", pcap_strerror(errno)); return PCAP_ERROR; } handlep->must_do_on_close |= MUST_CLEAR_PROMISC; /* * Add this to the list of pcaps * to close when we exit. */ pcap_add_to_pcaps_to_close(handle); } } /* * Compute the buffer size. * * We're using SOCK_PACKET, so this might be a 2.0[.x] * kernel, and might require special handling - check. */ if (uname(&utsname) < 0 || strncmp(utsname.release, "2.0", 3) == 0) { /* * Either we couldn't find out what kernel release * this is, or it's a 2.0[.x] kernel. * * In the 2.0[.x] kernel, a "recvfrom()" on * a SOCK_PACKET socket, with MSG_TRUNC set, will * return the number of bytes read, so if we pass * a length based on the snapshot length, it'll * return the number of bytes from the packet * copied to userland, not the actual length * of the packet. * * This means that, for example, the IP dissector * in tcpdump will get handed a packet length less * than the length in the IP header, and will * complain about "truncated-ip". * * So we don't bother trying to copy from the * kernel only the bytes in which we're interested, * but instead copy them all, just as the older * versions of libpcap for Linux did. * * The buffer therefore needs to be big enough to * hold the largest packet we can get from this * device. Unfortunately, we can't get the MRU * of the network; we can only get the MTU. The * MTU may be too small, in which case a packet larger * than the buffer size will be truncated *and* we * won't get the actual packet size. * * However, if the snapshot length is larger than * the buffer size based on the MTU, we use the * snapshot length as the buffer size, instead; * this means that with a sufficiently large snapshot * length we won't artificially truncate packets * to the MTU-based size. * * This mess just one of many problems with packet * capture on 2.0[.x] kernels; you really want a * 2.2[.x] or later kernel if you want packet capture * to work well. */ mtu = iface_get_mtu(handle->fd, device, handle->errbuf); if (mtu == -1) return PCAP_ERROR; handle->bufsize = MAX_LINKHEADER_SIZE + mtu; if (handle->bufsize < (u_int)handle->snapshot) handle->bufsize = (u_int)handle->snapshot; } else { /* * This is a 2.2[.x] or later kernel. * * We can safely pass "recvfrom()" a byte count * based on the snapshot length. */ handle->bufsize = (u_int)handle->snapshot; } /* * Default value for offset to align link-layer payload * on a 4-byte boundary. */ handle->offset = 0; /* * SOCK_PACKET sockets don't supply information from * stripped VLAN tags. */ handlep->vlan_offset = -1; /* unknown */ return 1; } /* * Bind the socket associated with FD to the given device using the * interface of the old kernels. */ static int iface_bind_old(int fd, const char *device, char *ebuf) { struct sockaddr saddr; int err; socklen_t errlen = sizeof(err); memset(&saddr, 0, sizeof(saddr)); strlcpy(saddr.sa_data, device, sizeof(saddr.sa_data)); if (bind(fd, &saddr, sizeof(saddr)) == -1) { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "bind: %s", pcap_strerror(errno)); return -1; } /* Any pending errors, e.g., network is down? */ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "getsockopt: %s", pcap_strerror(errno)); return -1; } if (err > 0) { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "bind: %s", pcap_strerror(err)); return -1; } return 0; } /* ===== System calls available on all supported kernels ============== */ /* * Query the kernel for the MTU of the given interface. */ static int iface_get_mtu(int fd, const char *device, char *ebuf) { struct ifreq ifr; if (!device) return BIGGER_THAN_ALL_MTUS; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCGIFMTU: %s", pcap_strerror(errno)); return -1; } return ifr.ifr_mtu; } /* * Get the hardware type of the given interface as ARPHRD_xxx constant. */ static int iface_get_arptype(int fd, const char *device, char *ebuf) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCGIFHWADDR: %s", pcap_strerror(errno)); if (errno == ENODEV) { /* * No such device. */ return PCAP_ERROR_NO_SUCH_DEVICE; } return PCAP_ERROR; } return ifr.ifr_hwaddr.sa_family; } #ifdef SO_ATTACH_FILTER static int fix_program(pcap_t *handle, struct sock_fprog *fcode, int is_mmapped) { struct pcap_linux *handlep = handle->priv; size_t prog_size; register int i; register struct bpf_insn *p; struct bpf_insn *f; int len; /* * Make a copy of the filter, and modify that copy if * necessary. */ prog_size = sizeof(*handle->fcode.bf_insns) * handle->fcode.bf_len; len = handle->fcode.bf_len; f = (struct bpf_insn *)malloc(prog_size); if (f == NULL) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return -1; } memcpy(f, handle->fcode.bf_insns, prog_size); fcode->len = len; fcode->filter = (struct sock_filter *) f; for (i = 0; i < len; ++i) { p = &f[i]; /* * What type of instruction is this? */ switch (BPF_CLASS(p->code)) { case BPF_RET: /* * It's a return instruction; are we capturing * in memory-mapped mode? */ if (!is_mmapped) { /* * No; is the snapshot length a constant, * rather than the contents of the * accumulator? */ if (BPF_MODE(p->code) == BPF_K) { /* * Yes - if the value to be returned, * i.e. the snapshot length, is * anything other than 0, make it * MAXIMUM_SNAPLEN, so that the packet * is truncated by "recvfrom()", * not by the filter. * * XXX - there's nothing we can * easily do if it's getting the * value from the accumulator; we'd * have to insert code to force * non-zero values to be * MAXIMUM_SNAPLEN. */ if (p->k != 0) p->k = MAXIMUM_SNAPLEN; } } break; case BPF_LD: case BPF_LDX: /* * It's a load instruction; is it loading * from the packet? */ switch (BPF_MODE(p->code)) { case BPF_ABS: case BPF_IND: case BPF_MSH: /* * Yes; are we in cooked mode? */ if (handlep->cooked) { /* * Yes, so we need to fix this * instruction. */ if (fix_offset(p) < 0) { /* * We failed to do so. * Return 0, so our caller * knows to punt to userland. */ return 0; } } break; } break; } } return 1; /* we succeeded */ } static int fix_offset(struct bpf_insn *p) { /* * What's the offset? */ if (p->k >= SLL_HDR_LEN) { /* * It's within the link-layer payload; that starts at an * offset of 0, as far as the kernel packet filter is * concerned, so subtract the length of the link-layer * header. */ p->k -= SLL_HDR_LEN; } else if (p->k == 0) { /* * It's the packet type field; map it to the special magic * kernel offset for that field. */ p->k = SKF_AD_OFF + SKF_AD_PKTTYPE; } else if (p->k == 14) { /* * It's the protocol field; map it to the special magic * kernel offset for that field. */ p->k = SKF_AD_OFF + SKF_AD_PROTOCOL; } else if ((bpf_int32)(p->k) > 0) { /* * It's within the header, but it's not one of those * fields; we can't do that in the kernel, so punt * to userland. */ return -1; } return 0; } static int set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode) { int total_filter_on = 0; int save_mode; int ret; int save_errno; /* * The socket filter code doesn't discard all packets queued * up on the socket when the filter is changed; this means * that packets that don't match the new filter may show up * after the new filter is put onto the socket, if those * packets haven't yet been read. * * This means, for example, that if you do a tcpdump capture * with a filter, the first few packets in the capture might * be packets that wouldn't have passed the filter. * * We therefore discard all packets queued up on the socket * when setting a kernel filter. (This isn't an issue for * userland filters, as the userland filtering is done after * packets are queued up.) * * To flush those packets, we put the socket in read-only mode, * and read packets from the socket until there are no more to * read. * * In order to keep that from being an infinite loop - i.e., * to keep more packets from arriving while we're draining * the queue - we put the "total filter", which is a filter * that rejects all packets, onto the socket before draining * the queue. * * This code deliberately ignores any errors, so that you may * get bogus packets if an error occurs, rather than having * the filtering done in userland even if it could have been * done in the kernel. */ if (setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER, &total_fcode, sizeof(total_fcode)) == 0) { char drain[1]; /* * Note that we've put the total filter onto the socket. */ total_filter_on = 1; /* * Save the socket's current mode, and put it in * non-blocking mode; we drain it by reading packets * until we get an error (which is normally a * "nothing more to be read" error). */ save_mode = fcntl(handle->fd, F_GETFL, 0); if (save_mode == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't get FD flags when changing filter: %s", pcap_strerror(errno)); return -2; } if (fcntl(handle->fd, F_SETFL, save_mode | O_NONBLOCK) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't set nonblocking mode when changing filter: %s", pcap_strerror(errno)); return -2; } while (recv(handle->fd, &drain, sizeof drain, MSG_TRUNC) >= 0) ; save_errno = errno; if (save_errno != EAGAIN) { /* * Fatal error. * * If we can't restore the mode or reset the * kernel filter, there's nothing we can do. */ (void)fcntl(handle->fd, F_SETFL, save_mode); (void)reset_kernel_filter(handle); pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "recv failed when changing filter: %s", pcap_strerror(save_errno)); return -2; } if (fcntl(handle->fd, F_SETFL, save_mode) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't restore FD flags when changing filter: %s", pcap_strerror(save_errno)); return -2; } } /* * Now attach the new filter. */ ret = setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER, fcode, sizeof(*fcode)); if (ret == -1 && total_filter_on) { /* * Well, we couldn't set that filter on the socket, * but we could set the total filter on the socket. * * This could, for example, mean that the filter was * too big to put into the kernel, so we'll have to * filter in userland; in any case, we'll be doing * filtering in userland, so we need to remove the * total filter so we see packets. */ save_errno = errno; /* * If this fails, we're really screwed; we have the * total filter on the socket, and it won't come off. * Report it as a fatal error. */ if (reset_kernel_filter(handle) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't remove kernel total filter: %s", pcap_strerror(errno)); return -2; /* fatal error */ } errno = save_errno; } return ret; } static int reset_kernel_filter(pcap_t *handle) { /* * setsockopt() barfs unless it get a dummy parameter. * valgrind whines unless the value is initialized, * as it has no idea that setsockopt() ignores its * parameter. */ int dummy = 0; return setsockopt(handle->fd, SOL_SOCKET, SO_DETACH_FILTER, &dummy, sizeof(dummy)); } #endif libpcap-1.8.1/org.tcpdump.chmod_bpf.plist0000644000026300017510000000067113003771737016531 0ustar mcrmcr Label org.tcpdump.chmod_bpf RunAtLoad Program /usr/local/bin/chmod_bpf ProgramArguments /usr/local/bin/chmod_bpf libpcap-1.8.1/pcap-bpf.c0000644000026300017510000023422513003771737013132 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1998 * 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* optionally get BSD define */ #ifdef HAVE_ZEROCOPY_BPF #include #endif #include #include /* * defines ioctls, but doesn't include . * * We include as it might be necessary to declare ioctl(); * at least on *BSD and Mac OS X, it also defines various SIOC ioctls - * we could include , but if we're already including * , which includes on those platforms, * there's not much point in doing so. * * If we have , we include it as well, to handle systems * such as Solaris which don't arrange to include if you * include */ #include #ifdef HAVE_SYS_IOCCOM_H #include #endif #include #if defined(__FreeBSD__) && defined(SIOCIFCREATE2) /* * Add support for capturing on FreeBSD usbusN interfaces. */ static const char usbus_prefix[] = "usbus"; #define USBUS_PREFIX_LEN (sizeof(usbus_prefix) - 1) #include #endif #ifdef HAVE_ZEROCOPY_BPF #include #endif #include #ifdef _AIX /* * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the * native OS version, as we need "struct bpf_config" from it. */ #define PCAP_DONT_INCLUDE_PCAP_BPF_H #include /* * Prevent bpf.h from redefining the DLT_ values to their * IFT_ values, as we're going to return the standard libpcap * values, not IBM's non-standard IFT_ values. */ #undef _AIX #include #define _AIX #include /* for IFT_ values */ #include #include #include #include #ifdef __64BIT__ #define domakedev makedev64 #define getmajor major64 #define bpf_hdr bpf_hdr32 #else /* __64BIT__ */ #define domakedev makedev #define getmajor major #endif /* __64BIT__ */ #define BPF_NAME "bpf" #define BPF_MINORS 4 #define DRIVER_PATH "/usr/lib/drivers" #define BPF_NODE "/dev/bpf" static int bpfloadedflag = 0; static int odmlockid = 0; static int bpf_load(char *errbuf); #else /* _AIX */ #include #endif /* _AIX */ #include #include #include #include #include #include #include #include #ifdef HAVE_NET_IF_MEDIA_H # include #endif #include "pcap-int.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif /* * Later versions of NetBSD stick padding in front of FDDI frames * to align the IP header on a 4-byte boundary. */ #if defined(__NetBSD__) && __NetBSD_Version__ > 106000000 #define PCAP_FDDIPAD 3 #endif /* * Private data for capturing on BPF devices. */ struct pcap_bpf { #ifdef HAVE_ZEROCOPY_BPF /* * Zero-copy read buffer -- for zero-copy BPF. 'buffer' above will * alternative between these two actual mmap'd buffers as required. * As there is a header on the front size of the mmap'd buffer, only * some of the buffer is exposed to libpcap as a whole via bufsize; * zbufsize is the true size. zbuffer tracks the current zbuf * assocated with buffer so that it can be used to decide which the * next buffer to read will be. */ u_char *zbuf1, *zbuf2, *zbuffer; u_int zbufsize; u_int zerocopy; u_int interrupted; struct timespec firstsel; /* * If there's currently a buffer being actively processed, then it is * referenced here; 'buffer' is also pointed at it, but offset by the * size of the header. */ struct bpf_zbuf_header *bzh; int nonblock; /* true if in nonblocking mode */ #endif /* HAVE_ZEROCOPY_BPF */ char *device; /* device name */ int filtering_in_kernel; /* using kernel filter */ int must_do_on_close; /* stuff we must do when we close */ }; /* * Stuff to do when we close. */ #define MUST_CLEAR_RFMON 0x00000001 /* clear rfmon (monitor) mode */ #define MUST_DESTROY_USBUS 0x00000002 /* destroy usbusN interface */ #ifdef BIOCGDLTLIST # if (defined(HAVE_NET_IF_MEDIA_H) && defined(IFM_IEEE80211)) && !defined(__APPLE__) #define HAVE_BSD_IEEE80211 /* * The ifm_ulist member of a struct ifmediareq is an int * on most systems, * but it's a uint64_t on newer versions of OpenBSD. * * We check this by checking whether IFM_GMASK is defined and > 2^32-1. */ # if defined(IFM_GMASK) && IFM_GMASK > 0xFFFFFFFF # define IFM_ULIST_TYPE uint64_t # else # define IFM_ULIST_TYPE int # endif # endif # if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) static int find_802_11(struct bpf_dltlist *); # ifdef HAVE_BSD_IEEE80211 static int monitor_mode(pcap_t *, int); # endif # if defined(__APPLE__) static void remove_en(pcap_t *); static void remove_802_11(pcap_t *); # endif # endif /* defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) */ #endif /* BIOCGDLTLIST */ #if defined(sun) && defined(LIFNAMSIZ) && defined(lifr_zoneid) #include #endif /* * We include the OS's , not our "pcap/bpf.h", so we probably * don't get DLT_DOCSIS defined. */ #ifndef DLT_DOCSIS #define DLT_DOCSIS 143 #endif /* * On OS X, we don't even get any of the 802.11-plus-radio-header DLT_'s * defined, even though some of them are used by various Airport drivers. */ #ifndef DLT_PRISM_HEADER #define DLT_PRISM_HEADER 119 #endif #ifndef DLT_AIRONET_HEADER #define DLT_AIRONET_HEADER 120 #endif #ifndef DLT_IEEE802_11_RADIO #define DLT_IEEE802_11_RADIO 127 #endif #ifndef DLT_IEEE802_11_RADIO_AVS #define DLT_IEEE802_11_RADIO_AVS 163 #endif static int pcap_can_set_rfmon_bpf(pcap_t *p); static int pcap_activate_bpf(pcap_t *p); static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp); static int pcap_setdirection_bpf(pcap_t *, pcap_direction_t); static int pcap_set_datalink_bpf(pcap_t *p, int dlt); /* * For zerocopy bpf, the setnonblock/getnonblock routines need to modify * pb->nonblock so we don't call select(2) if the pcap handle is in non- * blocking mode. */ static int pcap_getnonblock_bpf(pcap_t *p, char *errbuf) { #ifdef HAVE_ZEROCOPY_BPF struct pcap_bpf *pb = p->priv; if (pb->zerocopy) return (pb->nonblock); #endif return (pcap_getnonblock_fd(p, errbuf)); } static int pcap_setnonblock_bpf(pcap_t *p, int nonblock, char *errbuf) { #ifdef HAVE_ZEROCOPY_BPF struct pcap_bpf *pb = p->priv; if (pb->zerocopy) { pb->nonblock = nonblock; return (0); } #endif return (pcap_setnonblock_fd(p, nonblock, errbuf)); } #ifdef HAVE_ZEROCOPY_BPF /* * Zero-copy BPF buffer routines to check for and acknowledge BPF data in * shared memory buffers. * * pcap_next_zbuf_shm(): Check for a newly available shared memory buffer, * and set up p->buffer and cc to reflect one if available. Notice that if * there was no prior buffer, we select zbuf1 as this will be the first * buffer filled for a fresh BPF session. */ static int pcap_next_zbuf_shm(pcap_t *p, int *cc) { struct pcap_bpf *pb = p->priv; struct bpf_zbuf_header *bzh; if (pb->zbuffer == pb->zbuf2 || pb->zbuffer == NULL) { bzh = (struct bpf_zbuf_header *)pb->zbuf1; if (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen)) { pb->bzh = bzh; pb->zbuffer = (u_char *)pb->zbuf1; p->buffer = pb->zbuffer + sizeof(*bzh); *cc = bzh->bzh_kernel_len; return (1); } } else if (pb->zbuffer == pb->zbuf1) { bzh = (struct bpf_zbuf_header *)pb->zbuf2; if (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen)) { pb->bzh = bzh; pb->zbuffer = (u_char *)pb->zbuf2; p->buffer = pb->zbuffer + sizeof(*bzh); *cc = bzh->bzh_kernel_len; return (1); } } *cc = 0; return (0); } /* * pcap_next_zbuf() -- Similar to pcap_next_zbuf_shm(), except wait using * select() for data or a timeout, and possibly force rotation of the buffer * in the event we time out or are in immediate mode. Invoke the shared * memory check before doing system calls in order to avoid doing avoidable * work. */ static int pcap_next_zbuf(pcap_t *p, int *cc) { struct pcap_bpf *pb = p->priv; struct bpf_zbuf bz; struct timeval tv; struct timespec cur; fd_set r_set; int data, r; int expire, tmout; #define TSTOMILLI(ts) (((ts)->tv_sec * 1000) + ((ts)->tv_nsec / 1000000)) /* * Start out by seeing whether anything is waiting by checking the * next shared memory buffer for data. */ data = pcap_next_zbuf_shm(p, cc); if (data) return (data); /* * If a previous sleep was interrupted due to signal delivery, make * sure that the timeout gets adjusted accordingly. This requires * that we analyze when the timeout should be been expired, and * subtract the current time from that. If after this operation, * our timeout is less then or equal to zero, handle it like a * regular timeout. */ tmout = p->opt.timeout; if (tmout) (void) clock_gettime(CLOCK_MONOTONIC, &cur); if (pb->interrupted && p->opt.timeout) { expire = TSTOMILLI(&pb->firstsel) + p->opt.timeout; tmout = expire - TSTOMILLI(&cur); #undef TSTOMILLI if (tmout <= 0) { pb->interrupted = 0; data = pcap_next_zbuf_shm(p, cc); if (data) return (data); if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { (void) pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCROTZBUF: %s", strerror(errno)); return (PCAP_ERROR); } return (pcap_next_zbuf_shm(p, cc)); } } /* * No data in the buffer, so must use select() to wait for data or * the next timeout. Note that we only call select if the handle * is in blocking mode. */ if (!pb->nonblock) { FD_ZERO(&r_set); FD_SET(p->fd, &r_set); if (tmout != 0) { tv.tv_sec = tmout / 1000; tv.tv_usec = (tmout * 1000) % 1000000; } r = select(p->fd + 1, &r_set, NULL, NULL, p->opt.timeout != 0 ? &tv : NULL); if (r < 0 && errno == EINTR) { if (!pb->interrupted && p->opt.timeout) { pb->interrupted = 1; pb->firstsel = cur; } return (0); } else if (r < 0) { (void) pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "select: %s", strerror(errno)); return (PCAP_ERROR); } } pb->interrupted = 0; /* * Check again for data, which may exist now that we've either been * woken up as a result of data or timed out. Try the "there's data" * case first since it doesn't require a system call. */ data = pcap_next_zbuf_shm(p, cc); if (data) return (data); /* * Try forcing a buffer rotation to dislodge timed out or immediate * data. */ if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { (void) pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCROTZBUF: %s", strerror(errno)); return (PCAP_ERROR); } return (pcap_next_zbuf_shm(p, cc)); } /* * Notify kernel that we are done with the buffer. We don't reset zbuffer so * that we know which buffer to use next time around. */ static int pcap_ack_zbuf(pcap_t *p) { struct pcap_bpf *pb = p->priv; atomic_store_rel_int(&pb->bzh->bzh_user_gen, pb->bzh->bzh_kernel_gen); pb->bzh = NULL; p->buffer = NULL; return (0); } #endif /* HAVE_ZEROCOPY_BPF */ pcap_t * pcap_create_interface(const char *device _U_, char *ebuf) { pcap_t *p; p = pcap_create_common(ebuf, sizeof (struct pcap_bpf)); if (p == NULL) return (NULL); p->activate_op = pcap_activate_bpf; p->can_set_rfmon_op = pcap_can_set_rfmon_bpf; #ifdef BIOCSTSTAMP /* * We claim that we support microsecond and nanosecond time * stamps. */ p->tstamp_precision_count = 2; p->tstamp_precision_list = malloc(2 * sizeof(u_int)); if (p->tstamp_precision_list == NULL) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(p); return (NULL); } p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; #endif /* BIOCSTSTAMP */ return (p); } /* * On success, returns a file descriptor for a BPF device. * On failure, returns a PCAP_ERROR_ value, and sets p->errbuf. */ static int bpf_open(char *errbuf) { int fd; #ifdef HAVE_CLONING_BPF static const char device[] = "/dev/bpf"; #else int n = 0; char device[sizeof "/dev/bpf0000000000"]; #endif #ifdef _AIX /* * Load the bpf driver, if it isn't already loaded, * and create the BPF device entries, if they don't * already exist. */ if (bpf_load(errbuf) == PCAP_ERROR) return (PCAP_ERROR); #endif #ifdef HAVE_CLONING_BPF if ((fd = open(device, O_RDWR)) == -1 && (errno != EACCES || (fd = open(device, O_RDONLY)) == -1)) { if (errno == EACCES) fd = PCAP_ERROR_PERM_DENIED; else fd = PCAP_ERROR; pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "(cannot open device) %s: %s", device, pcap_strerror(errno)); } #else /* * Go through all the minors and find one that isn't in use. */ do { (void)pcap_snprintf(device, sizeof(device), "/dev/bpf%d", n++); /* * Initially try a read/write open (to allow the inject * method to work). If that fails due to permission * issues, fall back to read-only. This allows a * non-root user to be granted specific access to pcap * capabilities via file permissions. * * XXX - we should have an API that has a flag that * controls whether to open read-only or read-write, * so that denial of permission to send (or inability * to send, if sending packets isn't supported on * the device in question) can be indicated at open * time. */ fd = open(device, O_RDWR); if (fd == -1 && errno == EACCES) fd = open(device, O_RDONLY); } while (fd < 0 && errno == EBUSY); /* * XXX better message for all minors used */ if (fd < 0) { switch (errno) { case ENOENT: fd = PCAP_ERROR; if (n == 1) { /* * /dev/bpf0 doesn't exist, which * means we probably have no BPF * devices. */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "(there are no BPF devices)"); } else { /* * We got EBUSY on at least one * BPF device, so we have BPF * devices, but all the ones * that exist are busy. */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "(all BPF devices are busy)"); } break; case EACCES: /* * Got EACCES on the last device we tried, * and EBUSY on all devices before that, * if any. */ fd = PCAP_ERROR_PERM_DENIED; pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "(cannot open BPF device) %s: %s", device, pcap_strerror(errno)); break; default: /* * Some other problem. */ fd = PCAP_ERROR; pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "(cannot open BPF device) %s: %s", device, pcap_strerror(errno)); break; } } #endif return (fd); } /* * Open and bind to a device; used if we're not actually going to use * the device, but are just testing whether it can be opened, or opening * it to get information about it. * * Returns an error code on failure (always negative), and an FD for * the now-bound BPF device on success (always non-negative). */ static int bpf_open_and_bind(const char *name, char *errbuf) { int fd; struct ifreq ifr; /* * First, open a BPF device. */ fd = bpf_open(errbuf); if (fd < 0) return (fd); /* fd is the appropriate error code */ /* * Now bind to the device. */ (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { switch (errno) { case ENXIO: /* * There's no such device. */ close(fd); return (PCAP_ERROR_NO_SUCH_DEVICE); case ENETDOWN: /* * Return a "network down" indication, so that * the application can report that rather than * saying we had a mysterious failure and * suggest that they report a problem to the * libpcap developers. */ close(fd); return (PCAP_ERROR_IFACE_NOT_UP); default: pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", name, pcap_strerror(errno)); close(fd); return (PCAP_ERROR); } } /* * Success. */ return (fd); } #ifdef BIOCGDLTLIST static int get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf) { memset(bdlp, 0, sizeof(*bdlp)); if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) == 0) { u_int i; int is_ethernet; bdlp->bfl_list = (u_int *) malloc(sizeof(u_int) * (bdlp->bfl_len + 1)); if (bdlp->bfl_list == NULL) { (void)pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (PCAP_ERROR); } if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) < 0) { (void)pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLTLIST: %s", pcap_strerror(errno)); free(bdlp->bfl_list); return (PCAP_ERROR); } /* * OK, for real Ethernet devices, add DLT_DOCSIS to the * list, so that an application can let you choose it, * in case you're capturing DOCSIS traffic that a Cisco * Cable Modem Termination System is putting out onto * an Ethernet (it doesn't put an Ethernet header onto * the wire, it puts raw DOCSIS frames out on the wire * inside the low-level Ethernet framing). * * A "real Ethernet device" is defined here as a device * that has a link-layer type of DLT_EN10MB and that has * no alternate link-layer types; that's done to exclude * 802.11 interfaces (which might or might not be the * right thing to do, but I suspect it is - Ethernet <-> * 802.11 bridges would probably badly mishandle frames * that don't have Ethernet headers). * * On Solaris with BPF, Ethernet devices also offer * DLT_IPNET, so we, if DLT_IPNET is defined, we don't * treat it as an indication that the device isn't an * Ethernet. */ if (v == DLT_EN10MB) { is_ethernet = 1; for (i = 0; i < bdlp->bfl_len; i++) { if (bdlp->bfl_list[i] != DLT_EN10MB #ifdef DLT_IPNET && bdlp->bfl_list[i] != DLT_IPNET #endif ) { is_ethernet = 0; break; } } if (is_ethernet) { /* * We reserved one more slot at the end of * the list. */ bdlp->bfl_list[bdlp->bfl_len] = DLT_DOCSIS; bdlp->bfl_len++; } } } else { /* * EINVAL just means "we don't support this ioctl on * this device"; don't treat it as an error. */ if (errno != EINVAL) { (void)pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLTLIST: %s", pcap_strerror(errno)); return (PCAP_ERROR); } } return (0); } #endif static int pcap_can_set_rfmon_bpf(pcap_t *p) { #if defined(__APPLE__) struct utsname osinfo; struct ifreq ifr; int fd; #ifdef BIOCGDLTLIST struct bpf_dltlist bdl; #endif /* * The joys of monitor mode on OS X. * * Prior to 10.4, it's not supported at all. * * In 10.4, if adapter enN supports monitor mode, there's a * wltN adapter corresponding to it; you open it, instead of * enN, to get monitor mode. You get whatever link-layer * headers it supplies. * * In 10.5, and, we assume, later releases, if adapter enN * supports monitor mode, it offers, among its selectable * DLT_ values, values that let you get the 802.11 header; * selecting one of those values puts the adapter into monitor * mode (i.e., you can't get 802.11 headers except in monitor * mode, and you can't get Ethernet headers in monitor mode). */ if (uname(&osinfo) == -1) { /* * Can't get the OS version; just say "no". */ return (0); } /* * We assume osinfo.sysname is "Darwin", because * __APPLE__ is defined. We just check the version. */ if (osinfo.release[0] < '8' && osinfo.release[1] == '.') { /* * 10.3 (Darwin 7.x) or earlier. * Monitor mode not supported. */ return (0); } if (osinfo.release[0] == '8' && osinfo.release[1] == '.') { /* * 10.4 (Darwin 8.x). s/en/wlt/, and check * whether the device exists. */ if (strncmp(p->opt.device, "en", 2) != 0) { /* * Not an enN device; no monitor mode. */ return (0); } fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); return (PCAP_ERROR); } strlcpy(ifr.ifr_name, "wlt", sizeof(ifr.ifr_name)); strlcat(ifr.ifr_name, p->opt.device + 2, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { /* * No such device? */ close(fd); return (0); } close(fd); return (1); } #ifdef BIOCGDLTLIST /* * Everything else is 10.5 or later; for those, * we just open the enN device, and check whether * we have any 802.11 devices. * * First, open a BPF device. */ fd = bpf_open(p->errbuf); if (fd < 0) return (fd); /* fd is the appropriate error code */ /* * Now bind to the device. */ (void)strncpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { switch (errno) { case ENXIO: /* * There's no such device. */ close(fd); return (PCAP_ERROR_NO_SUCH_DEVICE); case ENETDOWN: /* * Return a "network down" indication, so that * the application can report that rather than * saying we had a mysterious failure and * suggest that they report a problem to the * libpcap developers. */ close(fd); return (PCAP_ERROR_IFACE_NOT_UP); default: pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", p->opt.device, pcap_strerror(errno)); close(fd); return (PCAP_ERROR); } } /* * We know the default link type -- now determine all the DLTs * this interface supports. If this fails with EINVAL, it's * not fatal; we just don't get to use the feature later. * (We don't care about DLT_DOCSIS, so we pass DLT_NULL * as the default DLT for this adapter.) */ if (get_dlt_list(fd, DLT_NULL, &bdl, p->errbuf) == PCAP_ERROR) { close(fd); return (PCAP_ERROR); } if (find_802_11(&bdl) != -1) { /* * We have an 802.11 DLT, so we can set monitor mode. */ free(bdl.bfl_list); close(fd); return (1); } free(bdl.bfl_list); close(fd); #endif /* BIOCGDLTLIST */ return (0); #elif defined(HAVE_BSD_IEEE80211) int ret; ret = monitor_mode(p, 0); if (ret == PCAP_ERROR_RFMON_NOTSUP) return (0); /* not an error, just a "can't do" */ if (ret == 0) return (1); /* success */ return (ret); #else return (0); #endif } static int pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps) { struct bpf_stat s; /* * "ps_recv" counts packets handed to the filter, not packets * that passed the filter. This includes packets later dropped * because we ran out of buffer space. * * "ps_drop" counts packets dropped inside the BPF device * because we ran out of buffer space. It doesn't count * packets dropped by the interface driver. It counts * only packets that passed the filter. * * Both statistics include packets not yet read from the kernel * by libpcap, and thus not yet seen by the application. */ if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s", pcap_strerror(errno)); return (PCAP_ERROR); } ps->ps_recv = s.bs_recv; ps->ps_drop = s.bs_drop; ps->ps_ifdrop = 0; return (0); } static int pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct pcap_bpf *pb = p->priv; int cc; int n = 0; register u_char *bp, *ep; u_char *datap; #ifdef PCAP_FDDIPAD register u_int pad; #endif #ifdef HAVE_ZEROCOPY_BPF int i; #endif again: /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that it * has, and return PCAP_ERROR_BREAK to indicate * that we were told to break out of the loop. */ p->break_loop = 0; return (PCAP_ERROR_BREAK); } cc = p->cc; if (p->cc == 0) { /* * When reading without zero-copy from a file descriptor, we * use a single buffer and return a length of data in the * buffer. With zero-copy, we update the p->buffer pointer * to point at whatever underlying buffer contains the next * data and update cc to reflect the data found in the * buffer. */ #ifdef HAVE_ZEROCOPY_BPF if (pb->zerocopy) { if (p->buffer != NULL) pcap_ack_zbuf(p); i = pcap_next_zbuf(p, &cc); if (i == 0) goto again; if (i < 0) return (PCAP_ERROR); } else #endif { cc = read(p->fd, p->buffer, p->bufsize); } if (cc < 0) { /* Don't choke when we get ptraced */ switch (errno) { case EINTR: goto again; #ifdef _AIX case EFAULT: /* * Sigh. More AIX wonderfulness. * * For some unknown reason the uiomove() * operation in the bpf kernel extension * used to copy the buffer into user * space sometimes returns EFAULT. I have * no idea why this is the case given that * a kernel debugger shows the user buffer * is correct. This problem appears to * be mostly mitigated by the memset of * the buffer before it is first used. * Very strange.... Shaun Clowes * * In any case this means that we shouldn't * treat EFAULT as a fatal error; as we * don't have an API for returning * a "some packets were dropped since * the last packet you saw" indication, * we just ignore EFAULT and keep reading. */ goto again; #endif case EWOULDBLOCK: return (0); case ENXIO: /* * The device on which we're capturing * went away. * * XXX - we should really return * PCAP_ERROR_IFACE_NOT_UP, but * pcap_dispatch() etc. aren't * defined to retur that. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The interface went down"); return (PCAP_ERROR); #if defined(sun) && !defined(BSD) && !defined(__svr4__) && !defined(__SVR4) /* * Due to a SunOS bug, after 2^31 bytes, the kernel * file offset overflows and read fails with EINVAL. * The lseek() to 0 will fix things. */ case EINVAL: if (lseek(p->fd, 0L, SEEK_CUR) + p->bufsize < 0) { (void)lseek(p->fd, 0L, SEEK_SET); goto again; } /* fall through */ #endif } pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read: %s", pcap_strerror(errno)); return (PCAP_ERROR); } bp = (u_char *)p->buffer; } else bp = p->bp; /* * Loop through each packet. */ #ifdef BIOCSTSTAMP #define bhp ((struct bpf_xhdr *)bp) #else #define bhp ((struct bpf_hdr *)bp) #endif ep = bp + cc; #ifdef PCAP_FDDIPAD pad = p->fddipad; #endif while (bp < ep) { register u_int caplen, hdrlen; /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return PCAP_ERROR_BREAK * to indicate that we were told to break out of the loop, * otherwise leave the flag set, so that the *next* call * will break out of the loop without having read any * packets, and return the number of packets we've * processed so far. */ if (p->break_loop) { p->bp = bp; p->cc = ep - bp; /* * ep is set based on the return value of read(), * but read() from a BPF device doesn't necessarily * return a value that's a multiple of the alignment * value for BPF_WORDALIGN(). However, whenever we * increment bp, we round up the increment value by * a value rounded up by BPF_WORDALIGN(), so we * could increment bp past ep after processing the * last packet in the buffer. * * We treat ep < bp as an indication that this * happened, and just set p->cc to 0. */ if (p->cc < 0) p->cc = 0; if (n == 0) { p->break_loop = 0; return (PCAP_ERROR_BREAK); } else return (n); } caplen = bhp->bh_caplen; hdrlen = bhp->bh_hdrlen; datap = bp + hdrlen; /* * Short-circuit evaluation: if using BPF filter * in kernel, no need to do it now - we already know * the packet passed the filter. * #ifdef PCAP_FDDIPAD * Note: the filter code was generated assuming * that p->fddipad was the amount of padding * before the header, as that's what's required * in the kernel, so we run the filter before * skipping that padding. #endif */ if (pb->filtering_in_kernel || bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) { struct pcap_pkthdr pkthdr; #ifdef BIOCSTSTAMP struct bintime bt; bt.sec = bhp->bh_tstamp.bt_sec; bt.frac = bhp->bh_tstamp.bt_frac; if (p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) { struct timespec ts; bintime2timespec(&bt, &ts); pkthdr.ts.tv_sec = ts.tv_sec; pkthdr.ts.tv_usec = ts.tv_nsec; } else { struct timeval tv; bintime2timeval(&bt, &tv); pkthdr.ts.tv_sec = tv.tv_sec; pkthdr.ts.tv_usec = tv.tv_usec; } #else pkthdr.ts.tv_sec = bhp->bh_tstamp.tv_sec; #ifdef _AIX /* * AIX's BPF returns seconds/nanoseconds time * stamps, not seconds/microseconds time stamps. */ pkthdr.ts.tv_usec = bhp->bh_tstamp.tv_usec/1000; #else pkthdr.ts.tv_usec = bhp->bh_tstamp.tv_usec; #endif #endif /* BIOCSTSTAMP */ #ifdef PCAP_FDDIPAD if (caplen > pad) pkthdr.caplen = caplen - pad; else pkthdr.caplen = 0; if (bhp->bh_datalen > pad) pkthdr.len = bhp->bh_datalen - pad; else pkthdr.len = 0; datap += pad; #else pkthdr.caplen = caplen; pkthdr.len = bhp->bh_datalen; #endif (*callback)(user, &pkthdr, datap); bp += BPF_WORDALIGN(caplen + hdrlen); if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { p->bp = bp; p->cc = ep - bp; /* * See comment above about p->cc < 0. */ if (p->cc < 0) p->cc = 0; return (n); } } else { /* * Skip this packet. */ bp += BPF_WORDALIGN(caplen + hdrlen); } } #undef bhp p->cc = 0; return (n); } static int pcap_inject_bpf(pcap_t *p, const void *buf, size_t size) { int ret; ret = write(p->fd, buf, size); #ifdef __APPLE__ if (ret == -1 && errno == EAFNOSUPPORT) { /* * In Mac OS X, there's a bug wherein setting the * BIOCSHDRCMPLT flag causes writes to fail; see, * for example: * * http://cerberus.sourcefire.com/~jeff/archives/patches/macosx/BIOCSHDRCMPLT-10.3.3.patch * * So, if, on OS X, we get EAFNOSUPPORT from the write, we * assume it's due to that bug, and turn off that flag * and try again. If we succeed, it either means that * somebody applied the fix from that URL, or other patches * for that bug from * * http://cerberus.sourcefire.com/~jeff/archives/patches/macosx/ * * and are running a Darwin kernel with those fixes, or * that Apple fixed the problem in some OS X release. */ u_int spoof_eth_src = 0; if (ioctl(p->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) { (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: can't turn off BIOCSHDRCMPLT: %s", pcap_strerror(errno)); return (PCAP_ERROR); } /* * Now try the write again. */ ret = write(p->fd, buf, size); } #endif /* __APPLE__ */ if (ret == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", pcap_strerror(errno)); return (PCAP_ERROR); } return (ret); } #ifdef _AIX static int bpf_odminit(char *errbuf) { char *errstr; if (odm_initialize() == -1) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_initialize failed: %s", errstr); return (PCAP_ERROR); } if ((odmlockid = odm_lock("/etc/objrepos/config_lock", ODM_WAIT)) == -1) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_lock of /etc/objrepos/config_lock failed: %s", errstr); (void)odm_terminate(); return (PCAP_ERROR); } return (0); } static int bpf_odmcleanup(char *errbuf) { char *errstr; if (odm_unlock(odmlockid) == -1) { if (errbuf != NULL) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_unlock failed: %s", errstr); } return (PCAP_ERROR); } if (odm_terminate() == -1) { if (errbuf != NULL) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_terminate failed: %s", errstr); } return (PCAP_ERROR); } return (0); } static int bpf_load(char *errbuf) { long major; int *minors; int numminors, i, rc; char buf[1024]; struct stat sbuf; struct bpf_config cfg_bpf; struct cfg_load cfg_ld; struct cfg_kmod cfg_km; /* * This is very very close to what happens in the real implementation * but I've fixed some (unlikely) bug situations. */ if (bpfloadedflag) return (0); if (bpf_odminit(errbuf) == PCAP_ERROR) return (PCAP_ERROR); major = genmajor(BPF_NAME); if (major == -1) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: genmajor failed: %s", pcap_strerror(errno)); (void)bpf_odmcleanup(NULL); return (PCAP_ERROR); } minors = getminor(major, &numminors, BPF_NAME); if (!minors) { minors = genminor("bpf", major, 0, BPF_MINORS, 1, 1); if (!minors) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: genminor failed: %s", pcap_strerror(errno)); (void)bpf_odmcleanup(NULL); return (PCAP_ERROR); } } if (bpf_odmcleanup(errbuf) == PCAP_ERROR) return (PCAP_ERROR); rc = stat(BPF_NODE "0", &sbuf); if (rc == -1 && errno != ENOENT) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: can't stat %s: %s", BPF_NODE "0", pcap_strerror(errno)); return (PCAP_ERROR); } if (rc == -1 || getmajor(sbuf.st_rdev) != major) { for (i = 0; i < BPF_MINORS; i++) { sprintf(buf, "%s%d", BPF_NODE, i); unlink(buf); if (mknod(buf, S_IRUSR | S_IFCHR, domakedev(major, i)) == -1) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: can't mknod %s: %s", buf, pcap_strerror(errno)); return (PCAP_ERROR); } } } /* Check if the driver is loaded */ memset(&cfg_ld, 0x0, sizeof(cfg_ld)); cfg_ld.path = buf; sprintf(cfg_ld.path, "%s/%s", DRIVER_PATH, BPF_NAME); if ((sysconfig(SYS_QUERYLOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) || (cfg_ld.kmid == 0)) { /* Driver isn't loaded, load it now */ if (sysconfig(SYS_SINGLELOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: could not load driver: %s", strerror(errno)); return (PCAP_ERROR); } } /* Configure the driver */ cfg_km.cmd = CFG_INIT; cfg_km.kmid = cfg_ld.kmid; cfg_km.mdilen = sizeof(cfg_bpf); cfg_km.mdiptr = (void *)&cfg_bpf; for (i = 0; i < BPF_MINORS; i++) { cfg_bpf.devno = domakedev(major, i); if (sysconfig(SYS_CFGKMOD, (void *)&cfg_km, sizeof(cfg_km)) == -1) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: could not configure driver: %s", strerror(errno)); return (PCAP_ERROR); } } bpfloadedflag = 1; return (0); } #endif /* * Undo any operations done when opening the device when necessary. */ static void pcap_cleanup_bpf(pcap_t *p) { struct pcap_bpf *pb = p->priv; #ifdef HAVE_BSD_IEEE80211 int sock; struct ifmediareq req; struct ifreq ifr; #endif if (pb->must_do_on_close != 0) { /* * There's something we have to do when closing this * pcap_t. */ #ifdef HAVE_BSD_IEEE80211 if (pb->must_do_on_close & MUST_CLEAR_RFMON) { /* * We put the interface into rfmon mode; * take it out of rfmon mode. * * XXX - if somebody else wants it in rfmon * mode, this code cannot know that, so it'll take * it out of rfmon mode. */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { fprintf(stderr, "Can't restore interface flags (socket() failed: %s).\n" "Please adjust manually.\n", strerror(errno)); } else { memset(&req, 0, sizeof(req)); strncpy(req.ifm_name, pb->device, sizeof(req.ifm_name)); if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { fprintf(stderr, "Can't restore interface flags (SIOCGIFMEDIA failed: %s).\n" "Please adjust manually.\n", strerror(errno)); } else { if (req.ifm_current & IFM_IEEE80211_MONITOR) { /* * Rfmon mode is currently on; * turn it off. */ memset(&ifr, 0, sizeof(ifr)); (void)strncpy(ifr.ifr_name, pb->device, sizeof(ifr.ifr_name)); ifr.ifr_media = req.ifm_current & ~IFM_IEEE80211_MONITOR; if (ioctl(sock, SIOCSIFMEDIA, &ifr) == -1) { fprintf(stderr, "Can't restore interface flags (SIOCSIFMEDIA failed: %s).\n" "Please adjust manually.\n", strerror(errno)); } } } close(sock); } } #endif /* HAVE_BSD_IEEE80211 */ #if defined(__FreeBSD__) && defined(SIOCIFCREATE2) /* * Attempt to destroy the usbusN interface that we created. */ if (pb->must_do_on_close & MUST_DESTROY_USBUS) { if (if_nametoindex(pb->device) > 0) { int s; s = socket(AF_LOCAL, SOCK_DGRAM, 0); if (s >= 0) { strlcpy(ifr.ifr_name, pb->device, sizeof(ifr.ifr_name)); ioctl(s, SIOCIFDESTROY, &ifr); close(s); } } } #endif /* defined(__FreeBSD__) && defined(SIOCIFCREATE2) */ /* * Take this pcap out of the list of pcaps for which we * have to take the interface out of some mode. */ pcap_remove_from_pcaps_to_close(p); pb->must_do_on_close = 0; } #ifdef HAVE_ZEROCOPY_BPF if (pb->zerocopy) { /* * Delete the mappings. Note that p->buffer gets * initialized to one of the mmapped regions in * this case, so do not try and free it directly; * null it out so that pcap_cleanup_live_common() * doesn't try to free it. */ if (pb->zbuf1 != MAP_FAILED && pb->zbuf1 != NULL) (void) munmap(pb->zbuf1, pb->zbufsize); if (pb->zbuf2 != MAP_FAILED && pb->zbuf2 != NULL) (void) munmap(pb->zbuf2, pb->zbufsize); p->buffer = NULL; } #endif if (pb->device != NULL) { free(pb->device); pb->device = NULL; } pcap_cleanup_live_common(p); } static int check_setif_failure(pcap_t *p, int error) { #ifdef __APPLE__ int fd; struct ifreq ifr; int err; #endif if (error == ENXIO) { /* * No such device exists. */ #ifdef __APPLE__ if (p->opt.rfmon && strncmp(p->opt.device, "wlt", 3) == 0) { /* * Monitor mode was requested, and we're trying * to open a "wltN" device. Assume that this * is 10.4 and that we were asked to open an * "enN" device; if that device exists, return * "monitor mode not supported on the device". */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd != -1) { strlcpy(ifr.ifr_name, "en", sizeof(ifr.ifr_name)); strlcat(ifr.ifr_name, p->opt.device + 3, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { /* * We assume this failed because * the underlying device doesn't * exist. */ err = PCAP_ERROR_NO_SUCH_DEVICE; pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFFLAGS on %s failed: %s", ifr.ifr_name, pcap_strerror(errno)); } else { /* * The underlying "enN" device * exists, but there's no * corresponding "wltN" device; * that means that the "enN" * device doesn't support * monitor mode, probably because * it's an Ethernet device rather * than a wireless device. */ err = PCAP_ERROR_RFMON_NOTSUP; } close(fd); } else { /* * We can't find out whether there's * an underlying "enN" device, so * just report "no such device". */ err = PCAP_ERROR_NO_SUCH_DEVICE; pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "socket() failed: %s", pcap_strerror(errno)); } return (err); } #endif /* * No such device. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF failed: %s", pcap_strerror(errno)); return (PCAP_ERROR_NO_SUCH_DEVICE); } else if (errno == ENETDOWN) { /* * Return a "network down" indication, so that * the application can report that rather than * saying we had a mysterious failure and * suggest that they report a problem to the * libpcap developers. */ return (PCAP_ERROR_IFACE_NOT_UP); } else { /* * Some other error; fill in the error string, and * return PCAP_ERROR. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", p->opt.device, pcap_strerror(errno)); return (PCAP_ERROR); } } /* * Default capture buffer size. * 32K isn't very much for modern machines with fast networks; we * pick .5M, as that's the maximum on at least some systems with BPF. * * However, on AIX 3.5, the larger buffer sized caused unrecoverable * read failures under stress, so we leave it as 32K; yet another * place where AIX's BPF is broken. */ #ifdef _AIX #define DEFAULT_BUFSIZE 32768 #else #define DEFAULT_BUFSIZE 524288 #endif static int pcap_activate_bpf(pcap_t *p) { struct pcap_bpf *pb = p->priv; int status = 0; #ifdef HAVE_BSD_IEEE80211 int retv; #endif int fd; #ifdef LIFNAMSIZ char *zonesep; struct lifreq ifr; char *ifrname = ifr.lifr_name; const size_t ifnamsiz = sizeof(ifr.lifr_name); #else struct ifreq ifr; char *ifrname = ifr.ifr_name; const size_t ifnamsiz = sizeof(ifr.ifr_name); #endif struct bpf_version bv; #ifdef __APPLE__ int sockfd; char *wltdev = NULL; #endif #ifdef BIOCGDLTLIST struct bpf_dltlist bdl; #if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) int new_dlt; #endif #endif /* BIOCGDLTLIST */ #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) u_int spoof_eth_src = 1; #endif u_int v; struct bpf_insn total_insn; struct bpf_program total_prog; struct utsname osinfo; int have_osinfo = 0; #ifdef HAVE_ZEROCOPY_BPF struct bpf_zbuf bz; u_int bufmode, zbufmax; #endif fd = bpf_open(p->errbuf); if (fd < 0) { status = fd; goto bad; } p->fd = fd; if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "kernel bpf filter out of date"); status = PCAP_ERROR; goto bad; } #if defined(LIFNAMSIZ) && defined(ZONENAME_MAX) && defined(lifr_zoneid) /* * Retrieve the zoneid of the zone we are currently executing in. */ if ((ifr.lifr_zoneid = getzoneid()) == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "getzoneid(): %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } /* * Check if the given source datalink name has a '/' separated * zonename prefix string. The zonename prefixed source datalink can * be used by pcap consumers in the Solaris global zone to capture * traffic on datalinks in non-global zones. Non-global zones * do not have access to datalinks outside of their own namespace. */ if ((zonesep = strchr(p->opt.device, '/')) != NULL) { char path_zname[ZONENAME_MAX]; int znamelen; char *lnamep; if (ifr.lifr_zoneid != GLOBAL_ZONEID) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "zonename/linkname only valid in global zone."); status = PCAP_ERROR; goto bad; } znamelen = zonesep - p->opt.device; (void) strlcpy(path_zname, p->opt.device, znamelen + 1); ifr.lifr_zoneid = getzoneidbyname(path_zname); if (ifr.lifr_zoneid == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "getzoneidbyname(%s): %s", path_zname, pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } lnamep = strdup(zonesep + 1); if (lnamep == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } free(p->opt.device); p->opt.device = lnamep; } #endif pb->device = strdup(p->opt.device); if (pb->device == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } /* * Attempt to find out the version of the OS on which we're running. */ if (uname(&osinfo) == 0) have_osinfo = 1; #ifdef __APPLE__ /* * See comment in pcap_can_set_rfmon_bpf() for an explanation * of why we check the version number. */ if (p->opt.rfmon) { if (have_osinfo) { /* * We assume osinfo.sysname is "Darwin", because * __APPLE__ is defined. We just check the version. */ if (osinfo.release[0] < '8' && osinfo.release[1] == '.') { /* * 10.3 (Darwin 7.x) or earlier. */ status = PCAP_ERROR_RFMON_NOTSUP; goto bad; } if (osinfo.release[0] == '8' && osinfo.release[1] == '.') { /* * 10.4 (Darwin 8.x). s/en/wlt/ */ if (strncmp(p->opt.device, "en", 2) != 0) { /* * Not an enN device; check * whether the device even exists. */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd != -1) { strlcpy(ifrname, p->opt.device, ifnamsiz); if (ioctl(sockfd, SIOCGIFFLAGS, (char *)&ifr) < 0) { /* * We assume this * failed because * the underlying * device doesn't * exist. */ status = PCAP_ERROR_NO_SUCH_DEVICE; pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFFLAGS failed: %s", pcap_strerror(errno)); } else status = PCAP_ERROR_RFMON_NOTSUP; close(sockfd); } else { /* * We can't find out whether * the device exists, so just * report "no such device". */ status = PCAP_ERROR_NO_SUCH_DEVICE; pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "socket() failed: %s", pcap_strerror(errno)); } goto bad; } wltdev = malloc(strlen(p->opt.device) + 2); if (wltdev == NULL) { (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } strcpy(wltdev, "wlt"); strcat(wltdev, p->opt.device + 2); free(p->opt.device); p->opt.device = wltdev; } /* * Everything else is 10.5 or later; for those, * we just open the enN device, and set the DLT. */ } } #endif /* __APPLE__ */ /* * If this is FreeBSD, and the device name begins with "usbus", * try to create the interface if it's not available. */ #if defined(__FreeBSD__) && defined(SIOCIFCREATE2) if (strncmp(p->opt.device, usbus_prefix, USBUS_PREFIX_LEN) == 0) { /* * Do we already have an interface with that name? */ if (if_nametoindex(p->opt.device) == 0) { /* * No. We need to create it, and, if we * succeed, remember that we should destroy * it when the pcap_t is closed. */ int s; /* * Open a socket to use for ioctls to * create the interface. */ s = socket(AF_LOCAL, SOCK_DGRAM, 0); if (s < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't open socket: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } /* * If we haven't already done so, arrange to have * "pcap_close_all()" called when we exit. */ if (!pcap_do_addexit(p)) { /* * "atexit()" failed; don't create the * interface, just give up. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "atexit failed"); close(s); status = PCAP_ERROR; goto bad; } /* * Create the interface. */ strlcpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) { if (errno == EINVAL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Invalid USB bus interface %s", p->opt.device); } else { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't create interface for %s: %s", p->opt.device, pcap_strerror(errno)); } close(s); status = PCAP_ERROR; goto bad; } /* * Make sure we clean this up when we close. */ pb->must_do_on_close |= MUST_DESTROY_USBUS; /* * Add this to the list of pcaps to close when we exit. */ pcap_add_to_pcaps_to_close(p); } } #endif /* defined(__FreeBSD__) && defined(SIOCIFCREATE2) */ #ifdef HAVE_ZEROCOPY_BPF /* * If the BPF extension to set buffer mode is present, try setting * the mode to zero-copy. If that fails, use regular buffering. If * it succeeds but other setup fails, return an error to the user. */ bufmode = BPF_BUFMODE_ZBUF; if (ioctl(fd, BIOCSETBUFMODE, (caddr_t)&bufmode) == 0) { /* * We have zerocopy BPF; use it. */ pb->zerocopy = 1; /* * How to pick a buffer size: first, query the maximum buffer * size supported by zero-copy. This also lets us quickly * determine whether the kernel generally supports zero-copy. * Then, if a buffer size was specified, use that, otherwise * query the default buffer size, which reflects kernel * policy for a desired default. Round to the nearest page * size. */ if (ioctl(fd, BIOCGETZMAX, (caddr_t)&zbufmax) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGETZMAX: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } if (p->opt.buffer_size != 0) { /* * A buffer size was explicitly specified; use it. */ v = p->opt.buffer_size; } else { if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < DEFAULT_BUFSIZE) v = DEFAULT_BUFSIZE; } #ifndef roundup #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */ #endif pb->zbufsize = roundup(v, getpagesize()); if (pb->zbufsize > zbufmax) pb->zbufsize = zbufmax; pb->zbuf1 = mmap(NULL, pb->zbufsize, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); pb->zbuf2 = mmap(NULL, pb->zbufsize, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); if (pb->zbuf1 == MAP_FAILED || pb->zbuf2 == MAP_FAILED) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "mmap: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } memset(&bz, 0, sizeof(bz)); /* bzero() deprecated, replaced with memset() */ bz.bz_bufa = pb->zbuf1; bz.bz_bufb = pb->zbuf2; bz.bz_buflen = pb->zbufsize; if (ioctl(fd, BIOCSETZBUF, (caddr_t)&bz) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETZBUF: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } (void)strncpy(ifrname, p->opt.device, ifnamsiz); if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", p->opt.device, pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } v = pb->zbufsize - sizeof(struct bpf_zbuf_header); } else #endif { /* * We don't have zerocopy BPF. * Set the buffer size. */ if (p->opt.buffer_size != 0) { /* * A buffer size was explicitly specified; use it. */ if (ioctl(fd, BIOCSBLEN, (caddr_t)&p->opt.buffer_size) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSBLEN: %s: %s", p->opt.device, pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } /* * Now bind to the device. */ (void)strncpy(ifrname, p->opt.device, ifnamsiz); #ifdef BIOCSETLIF if (ioctl(fd, BIOCSETLIF, (caddr_t)&ifr) < 0) #else if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) #endif { status = check_setif_failure(p, errno); goto bad; } } else { /* * No buffer size was explicitly specified. * * Try finding a good size for the buffer; * DEFAULT_BUFSIZE may be too big, so keep * cutting it in half until we find a size * that works, or run out of sizes to try. * If the default is larger, don't make it smaller. */ if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < DEFAULT_BUFSIZE) v = DEFAULT_BUFSIZE; for ( ; v != 0; v >>= 1) { /* * Ignore the return value - this is because the * call fails on BPF systems that don't have * kernel malloc. And if the call fails, it's * no big deal, we just continue to use the * standard buffer size. */ (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v); (void)strncpy(ifrname, p->opt.device, ifnamsiz); #ifdef BIOCSETLIF if (ioctl(fd, BIOCSETLIF, (caddr_t)&ifr) >= 0) #else if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0) #endif break; /* that size worked; we're done */ if (errno != ENOBUFS) { status = check_setif_failure(p, errno); goto bad; } } if (v == 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSBLEN: %s: No buffer size worked", p->opt.device); status = PCAP_ERROR; goto bad; } } } /* Get the data link layer type. */ if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } #ifdef _AIX /* * AIX's BPF returns IFF_ types, not DLT_ types, in BIOCGDLT. */ switch (v) { case IFT_ETHER: case IFT_ISO88023: v = DLT_EN10MB; break; case IFT_FDDI: v = DLT_FDDI; break; case IFT_ISO88025: v = DLT_IEEE802; break; case IFT_LOOP: v = DLT_NULL; break; default: /* * We don't know what to map this to yet. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u", v); status = PCAP_ERROR; goto bad; } #endif #if _BSDI_VERSION - 0 >= 199510 /* The SLIP and PPP link layer header changed in BSD/OS 2.1 */ switch (v) { case DLT_SLIP: v = DLT_SLIP_BSDOS; break; case DLT_PPP: v = DLT_PPP_BSDOS; break; case 11: /*DLT_FR*/ v = DLT_FRELAY; break; case 12: /*DLT_C_HDLC*/ v = DLT_CHDLC; break; } #endif #ifdef BIOCGDLTLIST /* * We know the default link type -- now determine all the DLTs * this interface supports. If this fails with EINVAL, it's * not fatal; we just don't get to use the feature later. */ if (get_dlt_list(fd, v, &bdl, p->errbuf) == -1) { status = PCAP_ERROR; goto bad; } p->dlt_count = bdl.bfl_len; p->dlt_list = bdl.bfl_list; #ifdef __APPLE__ /* * Monitor mode fun, continued. * * For 10.5 and, we're assuming, later releases, as noted above, * 802.1 adapters that support monitor mode offer both DLT_EN10MB, * DLT_IEEE802_11, and possibly some 802.11-plus-radio-information * DLT_ value. Choosing one of the 802.11 DLT_ values will turn * monitor mode on. * * Therefore, if the user asked for monitor mode, we filter out * the DLT_EN10MB value, as you can't get that in monitor mode, * and, if the user didn't ask for monitor mode, we filter out * the 802.11 DLT_ values, because selecting those will turn * monitor mode on. Then, for monitor mode, if an 802.11-plus- * radio DLT_ value is offered, we try to select that, otherwise * we try to select DLT_IEEE802_11. */ if (have_osinfo) { if (isdigit((unsigned)osinfo.release[0]) && (osinfo.release[0] == '9' || isdigit((unsigned)osinfo.release[1]))) { /* * 10.5 (Darwin 9.x), or later. */ new_dlt = find_802_11(&bdl); if (new_dlt != -1) { /* * We have at least one 802.11 DLT_ value, * so this is an 802.11 interface. * new_dlt is the best of the 802.11 * DLT_ values in the list. */ if (p->opt.rfmon) { /* * Our caller wants monitor mode. * Purge DLT_EN10MB from the list * of link-layer types, as selecting * it will keep monitor mode off. */ remove_en(p); /* * If the new mode we want isn't * the default mode, attempt to * select the new mode. */ if ((u_int)new_dlt != v) { if (ioctl(p->fd, BIOCSDLT, &new_dlt) != -1) { /* * We succeeded; * make this the * new DLT_ value. */ v = new_dlt; } } } else { /* * Our caller doesn't want * monitor mode. Unless this * is being done by pcap_open_live(), * purge the 802.11 link-layer types * from the list, as selecting * one of them will turn monitor * mode on. */ if (!p->oldstyle) remove_802_11(p); } } else { if (p->opt.rfmon) { /* * The caller requested monitor * mode, but we have no 802.11 * link-layer types, so they * can't have it. */ status = PCAP_ERROR_RFMON_NOTSUP; goto bad; } } } } #elif defined(HAVE_BSD_IEEE80211) /* * *BSD with the new 802.11 ioctls. * Do we want monitor mode? */ if (p->opt.rfmon) { /* * Try to put the interface into monitor mode. */ retv = monitor_mode(p, 1); if (retv != 0) { /* * We failed. */ status = retv; goto bad; } /* * We're in monitor mode. * Try to find the best 802.11 DLT_ value and, if we * succeed, try to switch to that mode if we're not * already in that mode. */ new_dlt = find_802_11(&bdl); if (new_dlt != -1) { /* * We have at least one 802.11 DLT_ value. * new_dlt is the best of the 802.11 * DLT_ values in the list. * * If the new mode we want isn't the default mode, * attempt to select the new mode. */ if ((u_int)new_dlt != v) { if (ioctl(p->fd, BIOCSDLT, &new_dlt) != -1) { /* * We succeeded; make this the * new DLT_ value. */ v = new_dlt; } } } } #endif /* various platforms */ #endif /* BIOCGDLTLIST */ /* * If this is an Ethernet device, and we don't have a DLT_ list, * give it a list with DLT_EN10MB and DLT_DOCSIS. (That'd give * 802.11 interfaces DLT_DOCSIS, which isn't the right thing to * do, but there's not much we can do about that without finding * some other way of determining whether it's an Ethernet or 802.11 * device.) */ if (v == DLT_EN10MB && p->dlt_count == 0) { p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (p->dlt_list != NULL) { p->dlt_list[0] = DLT_EN10MB; p->dlt_list[1] = DLT_DOCSIS; p->dlt_count = 2; } } #ifdef PCAP_FDDIPAD if (v == DLT_FDDI) p->fddipad = PCAP_FDDIPAD; else #endif p->fddipad = 0; p->linktype = v; #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) /* * Do a BIOCSHDRCMPLT, if defined, to turn that flag on, so * the link-layer source address isn't forcibly overwritten. * (Should we ignore errors? Should we do this only if * we're open for writing?) * * XXX - I seem to remember some packet-sending bug in some * BSDs - check CVS log for "bpf.c"? */ if (ioctl(fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) { (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSHDRCMPLT: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } #endif /* set timeout */ #ifdef HAVE_ZEROCOPY_BPF /* * In zero-copy mode, we just use the timeout in select(). * XXX - what if we're in non-blocking mode and the *application* * is using select() or poll() or kqueues or....? */ if (p->opt.timeout && !pb->zerocopy) { #else if (p->opt.timeout) { #endif /* * XXX - is this seconds/nanoseconds in AIX? * (Treating it as such doesn't fix the timeout * problem described below.) * * XXX - Mac OS X 10.6 mishandles BIOCSRTIMEOUT in * 64-bit userland - it takes, as an argument, a * "struct BPF_TIMEVAL", which has 32-bit tv_sec * and tv_usec, rather than a "struct timeval". * * If this platform defines "struct BPF_TIMEVAL", * we check whether the structure size in BIOCSRTIMEOUT * is that of a "struct timeval" and, if not, we use * a "struct BPF_TIMEVAL" rather than a "struct timeval". * (That way, if the bug is fixed in a future release, * we will still do the right thing.) */ struct timeval to; #ifdef HAVE_STRUCT_BPF_TIMEVAL struct BPF_TIMEVAL bpf_to; if (IOCPARM_LEN(BIOCSRTIMEOUT) != sizeof(struct timeval)) { bpf_to.tv_sec = p->opt.timeout / 1000; bpf_to.tv_usec = (p->opt.timeout * 1000) % 1000000; if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&bpf_to) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } } else { #endif to.tv_sec = p->opt.timeout / 1000; to.tv_usec = (p->opt.timeout * 1000) % 1000000; if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } #ifdef HAVE_STRUCT_BPF_TIMEVAL } #endif } #ifdef BIOCIMMEDIATE /* * Darren Reed notes that * * On AIX (4.2 at least), if BIOCIMMEDIATE is not set, the * timeout appears to be ignored and it waits until the buffer * is filled before returning. The result of not having it * set is almost worse than useless if your BPF filter * is reducing things to only a few packets (i.e. one every * second or so). * * so we always turn BIOCIMMEDIATE mode on if this is AIX. * * For other platforms, we don't turn immediate mode on by default, * as that would mean we get woken up for every packet, which * probably isn't what you want for a packet sniffer. * * We set immediate mode if the caller requested it by calling * pcap_set_immediate() before calling pcap_activate(). */ #ifndef _AIX if (p->opt.immediate) { #endif /* _AIX */ v = 1; if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCIMMEDIATE: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } #ifndef _AIX } #endif /* _AIX */ #else /* BIOCIMMEDIATE */ if (p->opt.immediate) { /* * We don't support immediate mode. Fail. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Immediate mode not supported"); status = PCAP_ERROR; goto bad; } #endif /* BIOCIMMEDIATE */ if (p->opt.promisc) { /* set promiscuous mode, just warn if it fails */ if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s", pcap_strerror(errno)); status = PCAP_WARNING_PROMISC_NOTSUP; } } #ifdef BIOCSTSTAMP v = BPF_T_BINTIME; if (ioctl(p->fd, BIOCSTSTAMP, &v) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSTSTAMP: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } #endif /* BIOCSTSTAMP */ if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } p->bufsize = v; #ifdef HAVE_ZEROCOPY_BPF if (!pb->zerocopy) { #endif p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } #ifdef _AIX /* For some strange reason this seems to prevent the EFAULT * problems we have experienced from AIX BPF. */ memset(p->buffer, 0x0, p->bufsize); #endif #ifdef HAVE_ZEROCOPY_BPF } #endif /* * If there's no filter program installed, there's * no indication to the kernel of what the snapshot * length should be, so no snapshotting is done. * * Therefore, when we open the device, we install * an "accept everything" filter with the specified * snapshot length. */ total_insn.code = (u_short)(BPF_RET | BPF_K); total_insn.jt = 0; total_insn.jf = 0; total_insn.k = p->snapshot; total_prog.bf_len = 1; total_prog.bf_insns = &total_insn; if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } /* * On most BPF platforms, either you can do a "select()" or * "poll()" on a BPF file descriptor and it works correctly, * or you can do it and it will return "readable" if the * hold buffer is full but not if the timeout expires *and* * a non-blocking read will, if the hold buffer is empty * but the store buffer isn't empty, rotate the buffers * and return what packets are available. * * In the latter case, the fact that a non-blocking read * will give you the available packets means you can work * around the failure of "select()" and "poll()" to wake up * and return "readable" when the timeout expires by using * the timeout as the "select()" or "poll()" timeout, putting * the BPF descriptor into non-blocking mode, and read from * it regardless of whether "select()" reports it as readable * or not. * * However, in FreeBSD 4.3 and 4.4, "select()" and "poll()" * won't wake up and return "readable" if the timer expires * and non-blocking reads return EWOULDBLOCK if the hold * buffer is empty, even if the store buffer is non-empty. * * This means the workaround in question won't work. * * Therefore, on FreeBSD 4.3 and 4.4, we set "p->selectable_fd" * to -1, which means "sorry, you can't use 'select()' or 'poll()' * here". On all other BPF platforms, we set it to the FD for * the BPF device; in NetBSD, OpenBSD, and Darwin, a non-blocking * read will, if the hold buffer is empty and the store buffer * isn't empty, rotate the buffers and return what packets are * there (and in sufficiently recent versions of OpenBSD * "select()" and "poll()" should work correctly). * * XXX - what about AIX? */ p->selectable_fd = p->fd; /* assume select() works until we know otherwise */ if (have_osinfo) { /* * We can check what OS this is. */ if (strcmp(osinfo.sysname, "FreeBSD") == 0) { if (strncmp(osinfo.release, "4.3-", 4) == 0 || strncmp(osinfo.release, "4.4-", 4) == 0) p->selectable_fd = -1; } } p->read_op = pcap_read_bpf; p->inject_op = pcap_inject_bpf; p->setfilter_op = pcap_setfilter_bpf; p->setdirection_op = pcap_setdirection_bpf; p->set_datalink_op = pcap_set_datalink_bpf; p->getnonblock_op = pcap_getnonblock_bpf; p->setnonblock_op = pcap_setnonblock_bpf; p->stats_op = pcap_stats_bpf; p->cleanup_op = pcap_cleanup_bpf; return (status); bad: pcap_cleanup_bpf(p); return (status); } /* * Not all interfaces can be bound to by BPF, so try to bind to * the specified interface; return 0 if we fail with * PCAP_ERROR_NO_SUCH_DEVICE (which means we got an ENXIO when we tried * to bind, which means this interface isn't in the list of interfaces * attached to BPF) and 1 otherwise. */ static int check_bpf_bindable(const char *name) { int fd; char errbuf[PCAP_ERRBUF_SIZE]; fd = bpf_open_and_bind(name, errbuf); if (fd < 0) { /* * Error - was it PCAP_ERROR_NO_SUCH_DEVICE? */ if (fd == PCAP_ERROR_NO_SUCH_DEVICE) { /* * Yes, so we can't bind to this because it's * not something supported by BPF. */ return (0); } /* * No, so we don't know whether it's supported or not; * say it is, so that the user can at least try to * open it and report the error (which is probably * "you don't have permission to open BPF devices"; * reporting those interfaces means users will ask * "why am I getting a permissions error when I try * to capture" rather than "why am I not seeing any * interfaces", making the underlying problem clearer). */ return (1); } /* * Success. */ close(fd); return (1); } #if defined(__FreeBSD__) && defined(SIOCIFCREATE2) static int finddevs_usb(pcap_if_t **alldevsp, char *errbuf) { DIR *usbdir; struct dirent *usbitem; size_t name_max; char *name; /* * We might have USB sniffing support, so try looking for USB * interfaces. * * We want to report a usbusN device for each USB bus, but * usbusN interfaces might, or might not, exist for them - * we create one if there isn't already one. * * So, instead, we look in /dev/usb for all buses and create * a "usbusN" device for each one. */ usbdir = opendir("/dev/usb"); if (usbdir == NULL) { /* * Just punt. */ return (0); } /* * Leave enough room for a 32-bit (10-digit) bus number. * Yes, that's overkill, but we won't be using * the buffer very long. */ name_max = USBUS_PREFIX_LEN + 10 + 1; name = malloc(name_max); if (name == NULL) { closedir(usbdir); return (0); } while ((usbitem = readdir(usbdir)) != NULL) { char *p; size_t busnumlen; int err; if (strcmp(usbitem->d_name, ".") == 0 || strcmp(usbitem->d_name, "..") == 0) { /* * Ignore these. */ continue; } p = strchr(usbitem->d_name, '.'); if (p == NULL) continue; busnumlen = p - usbitem->d_name; memcpy(name, usbus_prefix, USBUS_PREFIX_LEN); memcpy(name + USBUS_PREFIX_LEN, usbitem->d_name, busnumlen); *(name + USBUS_PREFIX_LEN + busnumlen) = '\0'; err = pcap_add_if(alldevsp, name, PCAP_IF_UP, NULL, errbuf); if (err != 0) { free(name); closedir(usbdir); return (err); } } free(name); closedir(usbdir); return (0); } #endif int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { /* * Get the list of regular interfaces first. */ if (pcap_findalldevs_interfaces(alldevsp, errbuf, check_bpf_bindable) == -1) return (-1); /* failure */ #if defined(__FreeBSD__) && defined(SIOCIFCREATE2) if (finddevs_usb(alldevsp, errbuf) == -1) return (-1); #endif return (0); } #ifdef HAVE_BSD_IEEE80211 static int monitor_mode(pcap_t *p, int set) { struct pcap_bpf *pb = p->priv; int sock; struct ifmediareq req; IFM_ULIST_TYPE *media_list; int i; int can_do; struct ifreq ifr; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't open socket: %s", pcap_strerror(errno)); return (PCAP_ERROR); } memset(&req, 0, sizeof req); strncpy(req.ifm_name, p->opt.device, sizeof req.ifm_name); /* * Find out how many media types we have. */ if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { /* * Can't get the media types. */ switch (errno) { case ENXIO: /* * There's no such device. */ close(sock); return (PCAP_ERROR_NO_SUCH_DEVICE); case EINVAL: /* * Interface doesn't support SIOC{G,S}IFMEDIA. */ close(sock); return (PCAP_ERROR_RFMON_NOTSUP); default: pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA 1: %s", pcap_strerror(errno)); close(sock); return (PCAP_ERROR); } } if (req.ifm_count == 0) { /* * No media types. */ close(sock); return (PCAP_ERROR_RFMON_NOTSUP); } /* * Allocate a buffer to hold all the media types, and * get the media types. */ media_list = malloc(req.ifm_count * sizeof(*media_list)); if (media_list == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); close(sock); return (PCAP_ERROR); } req.ifm_ulist = media_list; if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA: %s", pcap_strerror(errno)); free(media_list); close(sock); return (PCAP_ERROR); } /* * Look for an 802.11 "automatic" media type. * We assume that all 802.11 adapters have that media type, * and that it will carry the monitor mode supported flag. */ can_do = 0; for (i = 0; i < req.ifm_count; i++) { if (IFM_TYPE(media_list[i]) == IFM_IEEE80211 && IFM_SUBTYPE(media_list[i]) == IFM_AUTO) { /* OK, does it do monitor mode? */ if (media_list[i] & IFM_IEEE80211_MONITOR) { can_do = 1; break; } } } free(media_list); if (!can_do) { /* * This adapter doesn't support monitor mode. */ close(sock); return (PCAP_ERROR_RFMON_NOTSUP); } if (set) { /* * Don't just check whether we can enable monitor mode, * do so, if it's not already enabled. */ if ((req.ifm_current & IFM_IEEE80211_MONITOR) == 0) { /* * Monitor mode isn't currently on, so turn it on, * and remember that we should turn it off when the * pcap_t is closed. */ /* * If we haven't already done so, arrange to have * "pcap_close_all()" called when we exit. */ if (!pcap_do_addexit(p)) { /* * "atexit()" failed; don't put the interface * in monitor mode, just give up. */ close(sock); return (PCAP_ERROR); } memset(&ifr, 0, sizeof(ifr)); (void)strncpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); ifr.ifr_media = req.ifm_current | IFM_IEEE80211_MONITOR; if (ioctl(sock, SIOCSIFMEDIA, &ifr) == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSIFMEDIA: %s", pcap_strerror(errno)); close(sock); return (PCAP_ERROR); } pb->must_do_on_close |= MUST_CLEAR_RFMON; /* * Add this to the list of pcaps to close when we exit. */ pcap_add_to_pcaps_to_close(p); } } return (0); } #endif /* HAVE_BSD_IEEE80211 */ #if defined(BIOCGDLTLIST) && (defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)) /* * Check whether we have any 802.11 link-layer types; return the best * of the 802.11 link-layer types if we find one, and return -1 * otherwise. * * DLT_IEEE802_11_RADIO, with the radiotap header, is considered the * best 802.11 link-layer type; any of the other 802.11-plus-radio * headers are second-best; 802.11 with no radio information is * the least good. */ static int find_802_11(struct bpf_dltlist *bdlp) { int new_dlt; u_int i; /* * Scan the list of DLT_ values, looking for 802.11 values, * and, if we find any, choose the best of them. */ new_dlt = -1; for (i = 0; i < bdlp->bfl_len; i++) { switch (bdlp->bfl_list[i]) { case DLT_IEEE802_11: /* * 802.11, but no radio. * * Offer this, and select it as the new mode * unless we've already found an 802.11 * header with radio information. */ if (new_dlt == -1) new_dlt = bdlp->bfl_list[i]; break; case DLT_PRISM_HEADER: case DLT_AIRONET_HEADER: case DLT_IEEE802_11_RADIO_AVS: /* * 802.11 with radio, but not radiotap. * * Offer this, and select it as the new mode * unless we've already found the radiotap DLT_. */ if (new_dlt != DLT_IEEE802_11_RADIO) new_dlt = bdlp->bfl_list[i]; break; case DLT_IEEE802_11_RADIO: /* * 802.11 with radiotap. * * Offer this, and select it as the new mode. */ new_dlt = bdlp->bfl_list[i]; break; default: /* * Not 802.11. */ break; } } return (new_dlt); } #endif /* defined(BIOCGDLTLIST) && (defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)) */ #if defined(__APPLE__) && defined(BIOCGDLTLIST) /* * Remove DLT_EN10MB from the list of DLT_ values, as we're in monitor mode, * and DLT_EN10MB isn't supported in monitor mode. */ static void remove_en(pcap_t *p) { int i, j; /* * Scan the list of DLT_ values and discard DLT_EN10MB. */ j = 0; for (i = 0; i < p->dlt_count; i++) { switch (p->dlt_list[i]) { case DLT_EN10MB: /* * Don't offer this one. */ continue; default: /* * Just copy this mode over. */ break; } /* * Copy this DLT_ value to its new position. */ p->dlt_list[j] = p->dlt_list[i]; j++; } /* * Set the DLT_ count to the number of entries we copied. */ p->dlt_count = j; } /* * Remove 802.11 link-layer types from the list of DLT_ values, as * we're not in monitor mode, and those DLT_ values will switch us * to monitor mode. */ static void remove_802_11(pcap_t *p) { int i, j; /* * Scan the list of DLT_ values and discard 802.11 values. */ j = 0; for (i = 0; i < p->dlt_count; i++) { switch (p->dlt_list[i]) { case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_AIRONET_HEADER: case DLT_IEEE802_11_RADIO: case DLT_IEEE802_11_RADIO_AVS: /* * 802.11. Don't offer this one. */ continue; default: /* * Just copy this mode over. */ break; } /* * Copy this DLT_ value to its new position. */ p->dlt_list[j] = p->dlt_list[i]; j++; } /* * Set the DLT_ count to the number of entries we copied. */ p->dlt_count = j; } #endif /* defined(__APPLE__) && defined(BIOCGDLTLIST) */ static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp) { struct pcap_bpf *pb = p->priv; /* * Free any user-mode filter we might happen to have installed. */ pcap_freecode(&p->fcode); /* * Try to install the kernel filter. */ if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) == 0) { /* * It worked. */ pb->filtering_in_kernel = 1; /* filtering in the kernel */ /* * Discard any previously-received packets, as they might * have passed whatever filter was formerly in effect, but * might not pass this filter (BIOCSETF discards packets * buffered in the kernel, so you can lose packets in any * case). */ p->cc = 0; return (0); } /* * We failed. * * If it failed with EINVAL, that's probably because the program * is invalid or too big. Validate it ourselves; if we like it * (we currently allow backward branches, to support protochain), * run it in userland. (There's no notion of "too big" for * userland.) * * Otherwise, just give up. * XXX - if the copy of the program into the kernel failed, * we will get EINVAL rather than, say, EFAULT on at least * some kernels. */ if (errno != EINVAL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", pcap_strerror(errno)); return (-1); } /* * install_bpf_program() validates the program. * * XXX - what if we already have a filter in the kernel? */ if (install_bpf_program(p, fp) < 0) return (-1); pb->filtering_in_kernel = 0; /* filtering in userland */ return (0); } /* * Set direction flag: Which packets do we accept on a forwarding * single device? IN, OUT or both? */ static int pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) { #if defined(BIOCSDIRECTION) u_int direction; direction = (d == PCAP_D_IN) ? BPF_D_IN : ((d == PCAP_D_OUT) ? BPF_D_OUT : BPF_D_INOUT); if (ioctl(p->fd, BIOCSDIRECTION, &direction) == -1) { (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "Cannot set direction to %s: %s", (d == PCAP_D_IN) ? "PCAP_D_IN" : ((d == PCAP_D_OUT) ? "PCAP_D_OUT" : "PCAP_D_INOUT"), strerror(errno)); return (-1); } return (0); #elif defined(BIOCSSEESENT) u_int seesent; /* * We don't support PCAP_D_OUT. */ if (d == PCAP_D_OUT) { pcap_snprintf(p->errbuf, sizeof(p->errbuf), "Setting direction to PCAP_D_OUT is not supported on BPF"); return -1; } seesent = (d == PCAP_D_INOUT); if (ioctl(p->fd, BIOCSSEESENT, &seesent) == -1) { (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "Cannot set direction to %s: %s", (d == PCAP_D_INOUT) ? "PCAP_D_INOUT" : "PCAP_D_IN", strerror(errno)); return (-1); } return (0); #else (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "This system doesn't support BIOCSSEESENT, so the direction can't be set"); return (-1); #endif } static int pcap_set_datalink_bpf(pcap_t *p, int dlt) { #ifdef BIOCSDLT if (ioctl(p->fd, BIOCSDLT, &dlt) == -1) { (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "Cannot set DLT %d: %s", dlt, strerror(errno)); return (-1); } #endif return (0); } libpcap-1.8.1/pcap-tc.c0000644000026300017510000010332313003771737012763 0ustar mcrmcr/* * Copyright (c) 2008 CACE Technologies, Davis (California) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of CACE Technologies 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "pcap-tc.h" #include #include #include #include #ifdef _WIN32 #include #endif typedef TC_STATUS (TC_CALLCONV *TcFcnQueryPortList) (PTC_PORT *ppPorts, PULONG pLength); typedef TC_STATUS (TC_CALLCONV *TcFcnFreePortList) (TC_PORT *pPorts); typedef PCHAR (TC_CALLCONV *TcFcnStatusGetString) (TC_STATUS status); typedef PCHAR (TC_CALLCONV *TcFcnPortGetName) (TC_PORT port); typedef PCHAR (TC_CALLCONV *TcFcnPortGetDescription) (TC_PORT port); typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceOpenByName) (PCHAR name, PTC_INSTANCE pInstance); typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceClose) (TC_INSTANCE instance); typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceSetFeature) (TC_INSTANCE instance, ULONG feature, ULONG value); typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceQueryFeature) (TC_INSTANCE instance, ULONG feature, PULONG pValue); typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceReceivePackets) (TC_INSTANCE instance, PTC_PACKETS_BUFFER pBuffer); typedef HANDLE (TC_CALLCONV *TcFcnInstanceGetReceiveWaitHandle) (TC_INSTANCE instance); typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceTransmitPackets) (TC_INSTANCE instance, TC_PACKETS_BUFFER pBuffer); typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceQueryStatistics) (TC_INSTANCE instance, PTC_STATISTICS pStatistics); typedef TC_STATUS (TC_CALLCONV *TcFcnPacketsBufferCreate) (ULONG size, PTC_PACKETS_BUFFER pBuffer); typedef VOID (TC_CALLCONV *TcFcnPacketsBufferDestroy) (TC_PACKETS_BUFFER buffer); typedef TC_STATUS (TC_CALLCONV *TcFcnPacketsBufferQueryNextPacket)(TC_PACKETS_BUFFER buffer, PTC_PACKET_HEADER pHeader, PVOID *ppData); typedef TC_STATUS (TC_CALLCONV *TcFcnPacketsBufferCommitNextPacket)(TC_PACKETS_BUFFER buffer, PTC_PACKET_HEADER pHeader, PVOID pData); typedef VOID (TC_CALLCONV *TcFcnStatisticsDestroy) (TC_STATISTICS statistics); typedef TC_STATUS (TC_CALLCONV *TcFcnStatisticsUpdate) (TC_STATISTICS statistics); typedef TC_STATUS (TC_CALLCONV *TcFcnStatisticsQueryValue) (TC_STATISTICS statistics, ULONG counterId, PULONGLONG pValue); typedef enum LONG { TC_API_UNLOADED = 0, TC_API_LOADED, TC_API_CANNOT_LOAD, TC_API_LOADING } TC_API_LOAD_STATUS; typedef struct _TC_FUNCTIONS { TC_API_LOAD_STATUS LoadStatus; #ifdef _WIN32 HMODULE hTcApiDllHandle; #endif TcFcnQueryPortList QueryPortList; TcFcnFreePortList FreePortList; TcFcnStatusGetString StatusGetString; TcFcnPortGetName PortGetName; TcFcnPortGetDescription PortGetDescription; TcFcnInstanceOpenByName InstanceOpenByName; TcFcnInstanceClose InstanceClose; TcFcnInstanceSetFeature InstanceSetFeature; TcFcnInstanceQueryFeature InstanceQueryFeature; TcFcnInstanceReceivePackets InstanceReceivePackets; #ifdef _WIN32 TcFcnInstanceGetReceiveWaitHandle InstanceGetReceiveWaitHandle; #endif TcFcnInstanceTransmitPackets InstanceTransmitPackets; TcFcnInstanceQueryStatistics InstanceQueryStatistics; TcFcnPacketsBufferCreate PacketsBufferCreate; TcFcnPacketsBufferDestroy PacketsBufferDestroy; TcFcnPacketsBufferQueryNextPacket PacketsBufferQueryNextPacket; TcFcnPacketsBufferCommitNextPacket PacketsBufferCommitNextPacket; TcFcnStatisticsDestroy StatisticsDestroy; TcFcnStatisticsUpdate StatisticsUpdate; TcFcnStatisticsQueryValue StatisticsQueryValue; } TC_FUNCTIONS; static pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port); static int TcSetDatalink(pcap_t *p, int dlt); static int TcGetNonBlock(pcap_t *p, char *errbuf); static int TcSetNonBlock(pcap_t *p, int nonblock, char *errbuf); static void TcCleanup(pcap_t *p); static int TcInject(pcap_t *p, const void *buf, size_t size); static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user); static int TcStats(pcap_t *p, struct pcap_stat *ps); static int TcSetFilter(pcap_t *p, struct bpf_program *fp); #ifdef _WIN32 static struct pcap_stat *TcStatsEx(pcap_t *p, int *pcap_stat_size); static int TcSetBuff(pcap_t *p, int dim); static int TcSetMode(pcap_t *p, int mode); static int TcSetMinToCopy(pcap_t *p, int size); static HANDLE TcGetReceiveWaitHandle(pcap_t *p); static int TcOidGetRequest(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp); static int TcOidSetRequest(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp); static u_int TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue, int sync); static int TcSetUserBuffer(pcap_t *p, int size); static int TcLiveDump(pcap_t *p, char *filename, int maxsize, int maxpacks); static int TcLiveDumpEnded(pcap_t *p, int sync); static PAirpcapHandle TcGetAirPcapHandle(pcap_t *p); #endif #ifdef _WIN32 TC_FUNCTIONS g_TcFunctions = { TC_API_UNLOADED, /* LoadStatus */ NULL, /* hTcApiDllHandle */ NULL, /* QueryPortList */ NULL, /* FreePortList */ NULL, /* StatusGetString */ NULL, /* PortGetName */ NULL, /* PortGetDescription */ NULL, /* InstanceOpenByName */ NULL, /* InstanceClose */ NULL, /* InstanceSetFeature */ NULL, /* InstanceQueryFeature */ NULL, /* InstanceReceivePackets */ NULL, /* InstanceGetReceiveWaitHandle */ NULL, /* InstanceTransmitPackets */ NULL, /* InstanceQueryStatistics */ NULL, /* PacketsBufferCreate */ NULL, /* PacketsBufferDestroy */ NULL, /* PacketsBufferQueryNextPacket */ NULL, /* PacketsBufferCommitNextPacket */ NULL, /* StatisticsDestroy */ NULL, /* StatisticsUpdate */ NULL /* StatisticsQueryValue */ }; #else TC_FUNCTIONS g_TcFunctions = { TC_API_LOADED, /* LoadStatus */ TcQueryPortList, TcFreePortList, TcStatusGetString, TcPortGetName, TcPortGetDescription, TcInstanceOpenByName, TcInstanceClose, TcInstanceSetFeature, TcInstanceQueryFeature, TcInstanceReceivePackets, #ifdef _WIN32 TcInstanceGetReceiveWaitHandle, #endif TcInstanceTransmitPackets, TcInstanceQueryStatistics, TcPacketsBufferCreate, TcPacketsBufferDestroy, TcPacketsBufferQueryNextPacket, TcPacketsBufferCommitNextPacket, TcStatisticsDestroy, TcStatisticsUpdate, TcStatisticsQueryValue, }; #endif #define MAX_TC_PACKET_SIZE 9500 #pragma pack(push, 1) #define PPH_PH_FLAG_PADDING ((UCHAR)0x01) #define PPH_PH_VERSION ((UCHAR)0x00) typedef struct _PPI_PACKET_HEADER { UCHAR PphVersion; UCHAR PphFlags; USHORT PphLength; ULONG PphDlt; } PPI_PACKET_HEADER, *PPPI_PACKET_HEADER; typedef struct _PPI_FIELD_HEADER { USHORT PfhType; USHORT PfhLength; } PPI_FIELD_HEADER, *PPPI_FIELD_HEADER; #define PPI_FIELD_TYPE_AGGREGATION_EXTENSION ((UCHAR)0x08) typedef struct _PPI_FIELD_AGGREGATION_EXTENSION { ULONG InterfaceId; } PPI_FIELD_AGGREGATION_EXTENSION, *PPPI_FIELD_AGGREGATION_EXTENSION; #define PPI_FIELD_TYPE_802_3_EXTENSION ((UCHAR)0x09) #define PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT ((ULONG)0x00000001) typedef struct _PPI_FIELD_802_3_EXTENSION { ULONG Flags; ULONG Errors; } PPI_FIELD_802_3_EXTENSION, *PPPI_FIELD_802_3_EXTENSION; typedef struct _PPI_HEADER { PPI_PACKET_HEADER PacketHeader; PPI_FIELD_HEADER AggregationFieldHeader; PPI_FIELD_AGGREGATION_EXTENSION AggregationField; PPI_FIELD_HEADER Dot3FieldHeader; PPI_FIELD_802_3_EXTENSION Dot3Field; } PPI_HEADER, *PPPI_HEADER; #pragma pack(pop) #ifdef _WIN32 // // This wrapper around loadlibrary appends the system folder (usually c:\windows\system32) // to the relative path of the DLL, so that the DLL is always loaded from an absolute path // (It's no longer possible to load airpcap.dll from the application folder). // This solves the DLL Hijacking issue discovered in August 2010 // http://blog.metasploit.com/2010/08/exploiting-dll-hijacking-flaws.html // HMODULE LoadLibrarySafe(LPCTSTR lpFileName) { TCHAR path[MAX_PATH]; TCHAR fullFileName[MAX_PATH]; UINT res; HMODULE hModule = NULL; do { res = GetSystemDirectory(path, MAX_PATH); if (res == 0) { // // some bad failure occurred; // break; } if (res > MAX_PATH) { // // the buffer was not big enough // SetLastError(ERROR_INSUFFICIENT_BUFFER); break; } if (res + 1 + _tcslen(lpFileName) + 1 < MAX_PATH) { memcpy(fullFileName, path, res * sizeof(TCHAR)); fullFileName[res] = _T('\\'); memcpy(&fullFileName[res + 1], lpFileName, (_tcslen(lpFileName) + 1) * sizeof(TCHAR)); hModule = LoadLibrary(fullFileName); } else { SetLastError(ERROR_INSUFFICIENT_BUFFER); } }while(FALSE); return hModule; } /* * NOTE: this function should be called by the pcap functions that can theoretically * deal with the Tc library for the first time, namely listing the adapters and * opening one. All the other ones (close, read, write, set parameters) work * on an open instance of TC, so we do not care to call this function */ TC_API_LOAD_STATUS LoadTcFunctions(void) { TC_API_LOAD_STATUS currentStatus; do { currentStatus = InterlockedCompareExchange((LONG*)&g_TcFunctions.LoadStatus, TC_API_LOADING, TC_API_UNLOADED); while(currentStatus == TC_API_LOADING) { currentStatus = InterlockedCompareExchange((LONG*)&g_TcFunctions.LoadStatus, TC_API_LOADING, TC_API_LOADING); Sleep(10); } /* * at this point we are either in the LOADED state, unloaded state (i.e. we are the ones loading everything) * or in cannot load */ if(currentStatus == TC_API_LOADED) { return TC_API_LOADED; } if (currentStatus == TC_API_CANNOT_LOAD) { return TC_API_CANNOT_LOAD; } currentStatus = TC_API_CANNOT_LOAD; g_TcFunctions.hTcApiDllHandle = LoadLibrarySafe("TcApi.dll"); if (g_TcFunctions.hTcApiDllHandle == NULL) break; g_TcFunctions.QueryPortList = (TcFcnQueryPortList) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcQueryPortList"); g_TcFunctions.FreePortList = (TcFcnFreePortList) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcFreePortList"); g_TcFunctions.StatusGetString = (TcFcnStatusGetString) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatusGetString"); g_TcFunctions.PortGetName = (TcFcnPortGetName) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPortGetName"); g_TcFunctions.PortGetDescription = (TcFcnPortGetDescription) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPortGetDescription"); g_TcFunctions.InstanceOpenByName = (TcFcnInstanceOpenByName) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceOpenByName"); g_TcFunctions.InstanceClose = (TcFcnInstanceClose) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceClose"); g_TcFunctions.InstanceSetFeature = (TcFcnInstanceSetFeature) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceSetFeature"); g_TcFunctions.InstanceQueryFeature = (TcFcnInstanceQueryFeature) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryFeature"); g_TcFunctions.InstanceReceivePackets = (TcFcnInstanceReceivePackets) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceReceivePackets"); g_TcFunctions.InstanceGetReceiveWaitHandle = (TcFcnInstanceGetReceiveWaitHandle)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceGetReceiveWaitHandle"); g_TcFunctions.InstanceTransmitPackets = (TcFcnInstanceTransmitPackets)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceTransmitPackets"); g_TcFunctions.InstanceQueryStatistics = (TcFcnInstanceQueryStatistics)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryStatistics"); g_TcFunctions.PacketsBufferCreate = (TcFcnPacketsBufferCreate) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCreate"); g_TcFunctions.PacketsBufferDestroy = (TcFcnPacketsBufferDestroy) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferDestroy"); g_TcFunctions.PacketsBufferQueryNextPacket = (TcFcnPacketsBufferQueryNextPacket)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferQueryNextPacket"); g_TcFunctions.PacketsBufferCommitNextPacket = (TcFcnPacketsBufferCommitNextPacket)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCommitNextPacket"); g_TcFunctions.StatisticsDestroy = (TcFcnStatisticsDestroy) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsDestroy"); g_TcFunctions.StatisticsUpdate = (TcFcnStatisticsUpdate) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsUpdate"); g_TcFunctions.StatisticsQueryValue = (TcFcnStatisticsQueryValue) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsQueryValue"); if ( g_TcFunctions.QueryPortList == NULL || g_TcFunctions.FreePortList == NULL || g_TcFunctions.StatusGetString == NULL || g_TcFunctions.PortGetName == NULL || g_TcFunctions.PortGetDescription == NULL || g_TcFunctions.InstanceOpenByName == NULL || g_TcFunctions.InstanceClose == NULL || g_TcFunctions.InstanceSetFeature == NULL || g_TcFunctions.InstanceQueryFeature == NULL || g_TcFunctions.InstanceReceivePackets == NULL || g_TcFunctions.InstanceGetReceiveWaitHandle == NULL || g_TcFunctions.InstanceTransmitPackets == NULL || g_TcFunctions.InstanceQueryStatistics == NULL || g_TcFunctions.PacketsBufferCreate == NULL || g_TcFunctions.PacketsBufferDestroy == NULL || g_TcFunctions.PacketsBufferQueryNextPacket == NULL || g_TcFunctions.PacketsBufferCommitNextPacket == NULL || g_TcFunctions.StatisticsDestroy == NULL || g_TcFunctions.StatisticsUpdate == NULL || g_TcFunctions.StatisticsQueryValue == NULL ) { break; } /* * everything got loaded, yay!! */ currentStatus = TC_API_LOADED; }while(FALSE); if (currentStatus != TC_API_LOADED) { if (g_TcFunctions.hTcApiDllHandle != NULL) { FreeLibrary(g_TcFunctions.hTcApiDllHandle); g_TcFunctions.hTcApiDllHandle = NULL; } } InterlockedExchange((LONG*)&g_TcFunctions.LoadStatus, currentStatus); return currentStatus; } #else // static linking TC_API_LOAD_STATUS LoadTcFunctions(void) { return TC_API_LOADED; } #endif /* * Private data for capturing on TurboCap devices. */ struct pcap_tc { TC_INSTANCE TcInstance; TC_PACKETS_BUFFER TcPacketsBuffer; ULONG TcAcceptedCount; u_char *PpiPacket; }; int TcFindAllDevs(pcap_if_t **alldevsp, char *errbuf) { TC_API_LOAD_STATUS loadStatus; ULONG numPorts; PTC_PORT pPorts = NULL; TC_STATUS status; int result = 0; pcap_if_t *dev, *cursor; ULONG i; do { loadStatus = LoadTcFunctions(); if (loadStatus != TC_API_LOADED) { result = 0; break; } /* * enumerate the ports, and add them to the list */ status = g_TcFunctions.QueryPortList(&pPorts, &numPorts); if (status != TC_SUCCESS) { result = 0; break; } for (i = 0; i < numPorts; i++) { /* * transform the port into an entry in the list */ dev = TcCreatePcapIfFromPort(pPorts[i]); if (dev != NULL) { /* * append it at the end */ if (*alldevsp == NULL) { *alldevsp = dev; } else { for(cursor = *alldevsp; cursor->next != NULL; cursor = cursor->next); cursor->next = dev; } } } if (numPorts > 0) { /* * ignore the result here */ status = g_TcFunctions.FreePortList(pPorts); } }while(FALSE); return result; } static pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port) { CHAR *name; CHAR *description; pcap_if_t *newIf = NULL; newIf = (pcap_if_t*)malloc(sizeof(*newIf)); if (newIf == NULL) { return NULL; } memset(newIf, 0, sizeof(*newIf)); name = g_TcFunctions.PortGetName(port); description = g_TcFunctions.PortGetDescription(port); newIf->name = (char*)malloc(strlen(name) + 1); if (newIf->name == NULL) { free(newIf); return NULL; } newIf->description = (char*)malloc(strlen(description) + 1); if (newIf->description == NULL) { free(newIf->name); free(newIf); return NULL; } strcpy(newIf->name, name); strcpy(newIf->description, description); newIf->addresses = NULL; newIf->next = NULL; newIf->flags = 0; return newIf; } static int TcActivate(pcap_t *p) { struct pcap_tc *pt = p->priv; TC_STATUS status; ULONG timeout; PPPI_HEADER pPpiHeader; if (p->opt.rfmon) { /* * No monitor mode on Tc cards; they're Ethernet * capture adapters. */ return PCAP_ERROR_RFMON_NOTSUP; } pt->PpiPacket = malloc(sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE); if (pt->PpiPacket == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error allocating memory"); return PCAP_ERROR; } /* * Initialize the PPI fixed fields */ pPpiHeader = (PPPI_HEADER)pt->PpiPacket; pPpiHeader->PacketHeader.PphDlt = DLT_EN10MB; pPpiHeader->PacketHeader.PphLength = sizeof(PPI_HEADER); pPpiHeader->PacketHeader.PphFlags = 0; pPpiHeader->PacketHeader.PphVersion = 0; pPpiHeader->AggregationFieldHeader.PfhLength = sizeof(PPI_FIELD_AGGREGATION_EXTENSION); pPpiHeader->AggregationFieldHeader.PfhType = PPI_FIELD_TYPE_AGGREGATION_EXTENSION; pPpiHeader->Dot3FieldHeader.PfhLength = sizeof(PPI_FIELD_802_3_EXTENSION); pPpiHeader->Dot3FieldHeader.PfhType = PPI_FIELD_TYPE_802_3_EXTENSION; status = g_TcFunctions.InstanceOpenByName(p->opt.device, &pt->TcInstance); if (status != TC_SUCCESS) { /* Adapter detected but we are not able to open it. Return failure. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening TurboCap adapter: %s", g_TcFunctions.StatusGetString(status)); return PCAP_ERROR; } p->linktype = DLT_EN10MB; p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (p->dlt_list != NULL) { p->dlt_list[0] = DLT_EN10MB; p->dlt_list[1] = DLT_PPI; p->dlt_count = 2; } /* * ignore promiscuous mode * p->opt.promisc */ /* * ignore all the buffer sizes */ /* * enable reception */ status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_RX_STATUS, 1); if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions.StatusGetString(status)); goto bad; } /* * enable transmission */ status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_TX_STATUS, 1); /* * Ignore the error here. */ p->inject_op = TcInject; /* * if the timeout is -1, it means immediate return, no timeout * if the timeout is 0, it means INFINITE */ if (p->opt.timeout == 0) { timeout = 0xFFFFFFFF; } else if (p->opt.timeout < 0) { /* * we insert a minimal timeout here */ timeout = 10; } else { timeout = p->opt.timeout; } status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_READ_TIMEOUT, timeout); if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions.StatusGetString(status)); goto bad; } p->read_op = TcRead; p->setfilter_op = TcSetFilter; p->setdirection_op = NULL; /* Not implemented. */ p->set_datalink_op = TcSetDatalink; p->getnonblock_op = TcGetNonBlock; p->setnonblock_op = TcSetNonBlock; p->stats_op = TcStats; #ifdef _WIN32 p->stats_ex_op = TcStatsEx; p->setbuff_op = TcSetBuff; p->setmode_op = TcSetMode; p->setmintocopy_op = TcSetMinToCopy; p->getevent_op = TcGetReceiveWaitHandle; p->oid_get_request_op = TcOidGetRequest; p->oid_set_request_op = TcOidSetRequest; p->sendqueue_transmit_op = TcSendqueueTransmit; p->setuserbuffer_op = TcSetUserBuffer; p->live_dump_op = TcLiveDump; p->live_dump_ended_op = TcLiveDumpEnded; p->get_airpcap_handle_op = TcGetAirPcapHandle; #else p->selectable_fd = -1; #endif p->cleanup_op = TcCleanup; return 0; bad: TcCleanup(p); return PCAP_ERROR; } pcap_t * TcCreate(const char *device, char *ebuf, int *is_ours) { ULONG numPorts; PTC_PORT pPorts = NULL; TC_STATUS status; int is_tc; ULONG i; pcap_t *p; if (LoadTcFunctions() != TC_API_LOADED) { /* * XXX - report this as an error rather than as * "not a TurboCap device"? */ *is_ours = 0; return NULL; } /* * enumerate the ports, and add them to the list */ status = g_TcFunctions.QueryPortList(&pPorts, &numPorts); if (status != TC_SUCCESS) { /* * XXX - report this as an error rather than as * "not a TurboCap device"? */ *is_ours = 0; return NULL; } is_tc = FALSE; for (i = 0; i < numPorts; i++) { if (strcmp(g_TcFunctions.PortGetName(pPorts[i]), device) == 0) { is_tc = TRUE; break; } } if (numPorts > 0) { /* * ignore the result here */ (void)g_TcFunctions.FreePortList(pPorts); } if (!is_tc) { *is_ours = 0; return NULL; } /* OK, it's probably ours. */ *is_ours = 1; p = pcap_create_common(ebuf, sizeof (struct pcap_tc)); if (p == NULL) return NULL; p->activate_op = TcActivate; return p; } static int TcSetDatalink(pcap_t *p, int dlt) { /* * always return 0, as the check is done by pcap_set_datalink */ return 0; } static int TcGetNonBlock(pcap_t *p, char *errbuf) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Getting the non blocking status is not available for TurboCap ports"); pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Getting the non blocking status is not available for TurboCap ports"); return -1; } static int TcSetNonBlock(pcap_t *p, int nonblock, char *errbuf) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Setting the non blocking status is not available for TurboCap ports"); pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Setting the non blocking status is not available for TurboCap ports"); return -1; } static void TcCleanup(pcap_t *p) { struct pcap_tc *pt = p->priv; if (pt->TcPacketsBuffer != NULL) { g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer); pt->TcPacketsBuffer = NULL; } if (pt->TcInstance != NULL) { /* * here we do not check for the error values */ g_TcFunctions.InstanceClose(pt->TcInstance); pt->TcInstance = NULL; } if (pt->PpiPacket != NULL) { free(pt->PpiPacket); pt->PpiPacket = NULL; } pcap_cleanup_live_common(p); } /* Send a packet to the network */ static int TcInject(pcap_t *p, const void *buf, size_t size) { struct pcap_tc *pt = p->priv; TC_STATUS status; TC_PACKETS_BUFFER buffer; TC_PACKET_HEADER header; if (size >= 0xFFFF) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: the TurboCap API does not support packets larger than 64k"); return -1; } status = g_TcFunctions.PacketsBufferCreate(sizeof(TC_PACKET_HEADER) + TC_ALIGN_USHORT_TO_64BIT((USHORT)size), &buffer); if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); return -1; } /* * we assume that the packet is without the checksum, as common with WinPcap */ memset(&header, 0, sizeof(header)); header.Length = (USHORT)size; header.CapturedLength = header.Length; status = g_TcFunctions.PacketsBufferCommitNextPacket(buffer, &header, (PVOID)buf); if (status == TC_SUCCESS) { status = g_TcFunctions.InstanceTransmitPackets(pt->TcInstance, buffer); if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); } } else { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); } g_TcFunctions.PacketsBufferDestroy(buffer); if (status != TC_SUCCESS) { return -1; } else { return 0; } } static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct pcap_tc *pt = p->priv; TC_STATUS status; int n = 0; /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that it * has, and return -2 to indicate that we were * told to break out of the loop. */ p->break_loop = 0; return -2; } if (pt->TcPacketsBuffer == NULL) { status = g_TcFunctions.InstanceReceivePackets(pt->TcInstance, &pt->TcPacketsBuffer); if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); return -1; } } while (TRUE) { struct pcap_pkthdr hdr; TC_PACKET_HEADER tcHeader; PVOID data; ULONG filterResult; /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return -2 to indicate * that we were told to break out of the loop, otherwise * leave the flag set, so that the *next* call will break * out of the loop without having read any packets, and * return the number of packets we've processed so far. */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return -2; } else { return n; } } if (pt->TcPacketsBuffer == NULL) { break; } status = g_TcFunctions.PacketsBufferQueryNextPacket(pt->TcPacketsBuffer, &tcHeader, &data); if (status == TC_ERROR_END_OF_BUFFER) { g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer); pt->TcPacketsBuffer = NULL; break; } if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); return -1; } /* No underlaying filtering system. We need to filter on our own */ if (p->fcode.bf_insns) { filterResult = bpf_filter(p->fcode.bf_insns, data, tcHeader.Length, tcHeader.CapturedLength); if (filterResult == 0) { continue; } if (filterResult > tcHeader.CapturedLength) { filterResult = tcHeader.CapturedLength; } } else { filterResult = tcHeader.CapturedLength; } pt->TcAcceptedCount ++; hdr.ts.tv_sec = (bpf_u_int32)(tcHeader.Timestamp / (ULONGLONG)(1000 * 1000 * 1000)); hdr.ts.tv_usec = (bpf_u_int32)((tcHeader.Timestamp % (ULONGLONG)(1000 * 1000 * 1000)) / 1000); if (p->linktype == DLT_EN10MB) { hdr.caplen = filterResult; hdr.len = tcHeader.Length; (*callback)(user, &hdr, data); } else { PPPI_HEADER pPpiHeader = (PPPI_HEADER)pt->PpiPacket; PVOID data2 = pPpiHeader + 1; pPpiHeader->AggregationField.InterfaceId = TC_PH_FLAGS_RX_PORT_ID(tcHeader.Flags); pPpiHeader->Dot3Field.Errors = tcHeader.Errors; if (tcHeader.Flags & TC_PH_FLAGS_CHECKSUM) { pPpiHeader->Dot3Field.Flags = PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT; } else { pPpiHeader->Dot3Field.Flags = 0; } if (filterResult <= MAX_TC_PACKET_SIZE) { memcpy(data2, data, filterResult); hdr.caplen = sizeof(PPI_HEADER) + filterResult; hdr.len = sizeof(PPI_HEADER) + tcHeader.Length; } else { memcpy(data2, data, MAX_TC_PACKET_SIZE); hdr.caplen = sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE; hdr.len = sizeof(PPI_HEADER) + tcHeader.Length; } (*callback)(user, &hdr, pt->PpiPacket); } if (++n >= cnt && cnt > 0) { return n; } } return n; } static int TcStats(pcap_t *p, struct pcap_stat *ps) { struct pcap_tc *pt = p->priv; TC_STATISTICS statistics; TC_STATUS status; ULONGLONG counter; struct pcap_stat s; status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics); if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status); return -1; } memset(&s, 0, sizeof(s)); status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter); if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); return -1; } if (counter <= (ULONGLONG)0xFFFFFFFF) { s.ps_recv = (ULONG)counter; } else { s.ps_recv = 0xFFFFFFFF; } status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter); if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); return -1; } if (counter <= (ULONGLONG)0xFFFFFFFF) { s.ps_ifdrop = (ULONG)counter; s.ps_drop = (ULONG)counter; } else { s.ps_ifdrop = 0xFFFFFFFF; s.ps_drop = 0xFFFFFFFF; } #if defined(_WIN32) && defined(HAVE_REMOTE) s.ps_capt = pt->TcAcceptedCount; #endif *ps = s; return 0; } /* * We filter at user level, since the kernel driver does't process the packets */ static int TcSetFilter(pcap_t *p, struct bpf_program *fp) { if(!fp) { strncpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf)); return -1; } /* Install a user level filter */ if (install_bpf_program(p, fp) < 0) { pcap_snprintf(p->errbuf, sizeof(p->errbuf), "setfilter, unable to install the filter: %s", pcap_strerror(errno)); return -1; } return 0; } #ifdef _WIN32 static struct pcap_stat * TcStatsEx(pcap_t *p, int *pcap_stat_size) { struct pcap_tc *pt = p->priv; TC_STATISTICS statistics; TC_STATUS status; ULONGLONG counter; *pcap_stat_size = sizeof (p->stat); status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics); if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status); return NULL; } memset(&p->stat, 0, sizeof(p->stat)); status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter); if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); return NULL; } if (counter <= (ULONGLONG)0xFFFFFFFF) { p->stat.ps_recv = (ULONG)counter; } else { p->stat.ps_recv = 0xFFFFFFFF; } status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter); if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); return NULL; } if (counter <= (ULONGLONG)0xFFFFFFFF) { p->stat.ps_ifdrop = (ULONG)counter; p->stat.ps_drop = (ULONG)counter; } else { p->stat.ps_ifdrop = 0xFFFFFFFF; p->stat.ps_drop = 0xFFFFFFFF; } #ifdef HAVE_REMOTE p->stat.ps_capt = pt->TcAcceptedCount; #endif return &p->stat; } /* Set the dimension of the kernel-level capture buffer */ static int TcSetBuff(pcap_t *p, int dim) { /* * XXX turbocap has an internal way of managing buffers. * And at the moment it's not configurable, so we just * silently ignore the request to set the buffer. */ return 0; } static int TcSetMode(pcap_t *p, int mode) { if (mode != MODE_CAPT) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mode %u not supported by TurboCap devices. TurboCap only supports capture.", mode); return -1; } return 0; } static int TcSetMinToCopy(pcap_t *p, int size) { struct pcap_tc *pt = p->priv; TC_STATUS status; if (size < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mintocopy cannot be less than 0."); return -1; } status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_MINTOCOPY, (ULONG)size); if (status != TC_SUCCESS) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions.StatusGetString(status), status); } return 0; } static HANDLE TcGetReceiveWaitHandle(pcap_t *p) { struct pcap_tc *pt = p->priv; return g_TcFunctions.InstanceGetReceiveWaitHandle(pt->TcInstance); } static int TcOidGetRequest(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, size_t *lenp _U_) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "An OID get request cannot be performed on a TurboCap device"); return PCAP_ERROR; } static int TcOidSetRequest(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_, size_t *lenp _U_) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "An OID set request cannot be performed on a TurboCap device"); return PCAP_ERROR; } static u_int TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Packets cannot be bulk transmitted on a TurboCap device"); return 0; } static int TcSetUserBuffer(pcap_t *p, int size _U_) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The user buffer cannot be set on a TurboCap device"); return -1; } static int TcLiveDump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Live packet dumping cannot be performed on a TurboCap device"); return -1; } static int TcLiveDumpEnded(pcap_t *p, int sync _U_) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Live packet dumping cannot be performed on a TurboCap device"); return -1; } static PAirpcapHandle TcGetAirPcapHandle(pcap_t *p _U_) { return NULL; } #endif libpcap-1.8.1/pcap_open_offline.3pcap.in0000644000026300017510000000706113003771737016275 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_OPEN_OFFLINE 3PCAP "3 January 2014" .SH NAME pcap_open_offline, pcap_open_offline_with_tstamp_precision, pcap_fopen_offline, pcap_fopen_offline_with_tstamp_precision \- open a saved capture file for reading .SH SYNOPSIS .nf .ft B #include .ft .LP .nf .ft B char errbuf[PCAP_ERRBUF_SIZE]; .ft .LP .ft B pcap_t *pcap_open_offline(const char *fname, char *errbuf); pcap_t *pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision, char *errbuf); pcap_t *pcap_fopen_offline(FILE *fp, char *errbuf); pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision, char *errbuf); .ft .fi .SH DESCRIPTION .B pcap_open_offline() and .B pcap_open_offline_with_tstamp_precision() are called to open a ``savefile'' for reading. .PP .I fname specifies the name of the file to open. The file can have the pcap file format as described in .BR pcap-savefile (@MAN_FILE_FORMATS@), which is the file format used by, among other programs, .BR tcpdump (1) and .BR tcpslice (1), or can have the pcap-ng file format, although not all pcap-ng files can be read. The name "-" is a synonym for .BR stdin . .PP .B pcap_open_offline_with_tstamp_precision() takes an additional .I precision argument specifying the time stamp precision desired; if .B PCAP_TSTAMP_PRECISION_MICRO is specified, packet time stamps will be supplied in seconds and microseconds, and if .B PCAP_TSTAMP_PRECISION_NANO is specified, packet time stamps will be supplied in seconds and nanoseconds. If the time stamps in the file do not have the same precision as the requested precision, they will be scaled up or down as necessary before being supplied. .PP Alternatively, you may call .B pcap_fopen_offline() or .B pcap_fopen_offline_with_tstamp_precision() to read dumped data from an existing open stream .IR fp . .B pcap_fopen_offline_with_tstamp_precision() takes an additional .I precision argument as described above. Note that on Windows, that stream should be opened in binary mode. .SH RETURN VALUE .BR pcap_open_offline() , .BR pcap_open_offline_with_tstamp_precision() , .BR pcap_fopen_offline() , and .B pcap_fopen_offline_with_tstamp_precision() return a .I pcap_t * on success and .B NULL on failure. If .B NULL is returned, .I errbuf is filled in with an appropriate error message. .I errbuf is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. .SH SEE ALSO pcap(3PCAP), pcap-savefile(@MAN_FILE_FORMATS@) libpcap-1.8.1/pcap_list_datalinks.3pcap.in0000644000026300017510000000504713003771737016641 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_LIST_DATALINKS 3PCAP "8 March 2015" .SH NAME pcap_list_datalinks, pcap_free_datalinks \- get a list of link-layer header types supported by a capture device, and free that list .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_list_datalinks(pcap_t *p, int **dlt_buf); void pcap_free_datalinks(int *dlt_list); .ft .fi .SH DESCRIPTION .B pcap_list_datalinks() is used to get a list of the supported link-layer header types of the interface associated with the pcap descriptor. .B pcap_list_datalinks() allocates an array to hold the list and sets .IR *dlt_buf to point to that array. .LP The caller is responsible for freeing the array with .BR pcap_free_datalinks() , which frees the list of link-layer header types pointed to by .IR dlt_list . .LP It must not be called on a pcap descriptor created by .B pcap_create() that has not yet been activated by .BR pcap_activate() . .SH RETURN VALUE .B pcap_list_datalinks() returns the number of link-layer header types in the array on success, .B PCAP_ERROR_NOT_ACTIVATED if called on a capture handle that has been created but not activated, and .B PCAP_ERROR (\-1) on other errors. If .B PCAP_ERROR is returned, .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO pcap(3PCAP), pcap_geterr(3PCAP), pcap_datalink_val_to_name(3PCAP), pcap-linktype(@MAN_MISC_INFO@) libpcap-1.8.1/remote-ext.h0000644000026300017510000003630413003771737013536 0ustar mcrmcr/* * Copyright (c) 2002 - 2003 * NetGroup, Politecnico di Torino (Italy) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __REMOTE_EXT_H__ #define __REMOTE_EXT_H__ #ifndef HAVE_REMOTE #error Please do not include this file directly. Just define HAVE_REMOTE and then include pcap.h #endif /*// Definition for Microsoft Visual Studio */ #if _MSC_VER > 1000 #pragma once #endif #ifdef __cplusplus extern "C" { #endif /* * \file remote-ext.h * * The goal of this file it to include most of the new definitions that should be * placed into the pcap.h file. * * It includes all new definitions (structures and functions like pcap_open(). * Some of the functions are not really a remote feature, but, right now, * they are placed here. */ /*// All this stuff is public */ /* * \addtogroup remote_struct * \{ */ /* * \brief Defines the maximum buffer size in which address, port, interface names are kept. * * In case the adapter name or such is larger than this value, it is truncated. * This is not used by the user; however it must be aware that an hostname / interface * name longer than this value will be truncated. */ #define PCAP_BUF_SIZE 1024 /* * \addtogroup remote_source_ID * \{ */ /* * \brief Internal representation of the type of source in use (file, * remote/local interface). * * This indicates a file, i.e. the user want to open a capture from a local file. */ #define PCAP_SRC_FILE 2 /* * \brief Internal representation of the type of source in use (file, * remote/local interface). * * This indicates a local interface, i.e. the user want to open a capture from * a local interface. This does not involve the RPCAP protocol. */ #define PCAP_SRC_IFLOCAL 3 /* * \brief Internal representation of the type of source in use (file, * remote/local interface). * * This indicates a remote interface, i.e. the user want to open a capture from * an interface on a remote host. This does involve the RPCAP protocol. */ #define PCAP_SRC_IFREMOTE 4 /* * \} */ /* \addtogroup remote_source_string * * The formats allowed by the pcap_open() are the following: * - file://path_and_filename [opens a local file] * - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol] * - rpcap://host/devicename [opens the selected device available on a remote host] * - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP] * - adaptername [to open a local adapter; kept for compability, but it is strongly discouraged] * - (NULL) [to open the first local adapter; kept for compability, but it is strongly discouraged] * * The formats allowed by the pcap_findalldevs_ex() are the following: * - file://folder/ [lists all the files in the given folder] * - rpcap:// [lists all local adapters] * - rpcap://host:port/ [lists the devices available on a remote host] * * Referring to the 'host' and 'port' parameters, they can be either numeric or literal. Since * IPv6 is fully supported, these are the allowed formats: * * - host (literal): e.g. host.foo.bar * - host (numeric IPv4): e.g. 10.11.12.13 * - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13] * - host (numeric IPv6): e.g. [1:2:3::4] * - port: can be either numeric (e.g. '80') or literal (e.g. 'http') * * Here you find some allowed examples: * - rpcap://host.foo.bar/devicename [everything literal, no port number] * - rpcap://host.foo.bar:1234/devicename [everything literal, with port number] * - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number] * - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number] * - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number] * - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number] * - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number] * - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number] * * \{ */ /* * \brief String that will be used to determine the type of source in use (file, * remote/local interface). * * This string will be prepended to the interface name in order to create a string * that contains all the information required to open the source. * * This string indicates that the user wants to open a capture from a local file. */ #define PCAP_SRC_FILE_STRING "file://" /* * \brief String that will be used to determine the type of source in use (file, * remote/local interface). * * This string will be prepended to the interface name in order to create a string * that contains all the information required to open the source. * * This string indicates that the user wants to open a capture from a network interface. * This string does not necessarily involve the use of the RPCAP protocol. If the * interface required resides on the local host, the RPCAP protocol is not involved * and the local functions are used. */ #define PCAP_SRC_IF_STRING "rpcap://" /* * \} */ /* * \addtogroup remote_open_flags * \{ */ /* * \brief Defines if the adapter has to go in promiscuous mode. * * It is '1' if you have to open the adapter in promiscuous mode, '0' otherwise. * Note that even if this parameter is false, the interface could well be in promiscuous * mode for some other reason (for example because another capture process with * promiscuous mode enabled is currently using that interface). * On on Linux systems with 2.2 or later kernels (that have the "any" device), this * flag does not work on the "any" device; if an argument of "any" is supplied, * the 'promisc' flag is ignored. */ #define PCAP_OPENFLAG_PROMISCUOUS 1 /* * \brief Defines if the data transfer (in case of a remote * capture) has to be done with UDP protocol. * * If it is '1' if you want a UDP data connection, '0' if you want * a TCP data connection; control connection is always TCP-based. * A UDP connection is much lighter, but it does not guarantee that all * the captured packets arrive to the client workstation. Moreover, * it could be harmful in case of network congestion. * This flag is meaningless if the source is not a remote interface. * In that case, it is simply ignored. */ #define PCAP_OPENFLAG_DATATX_UDP 2 /* * \brief Defines if the remote probe will capture its own generated traffic. * * In case the remote probe uses the same interface to capture traffic and to send * data back to the caller, the captured traffic includes the RPCAP traffic as well. * If this flag is turned on, the RPCAP traffic is excluded from the capture, so that * the trace returned back to the collector is does not include this traffic. */ #define PCAP_OPENFLAG_NOCAPTURE_RPCAP 4 /* * \brief Defines if the local adapter will capture its own generated traffic. * * This flag tells the underlying capture driver to drop the packets that were sent by itself. * This is useful when building applications like bridges, that should ignore the traffic * they just sent. */ #define PCAP_OPENFLAG_NOCAPTURE_LOCAL 8 /* * \brief This flag configures the adapter for maximum responsiveness. * * In presence of a large value for nbytes, WinPcap waits for the arrival of several packets before * copying the data to the user. This guarantees a low number of system calls, i.e. lower processor usage, * i.e. better performance, which is good for applications like sniffers. If the user sets the * PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will copy the packets as soon as the application * is ready to receive them. This is suggested for real time applications (like, for example, a bridge) * that need the best responsiveness. */ #define PCAP_OPENFLAG_MAX_RESPONSIVENESS 16 /* * \} */ /* * \addtogroup remote_samp_methods * \{ */ /* *\brief No sampling has to be done on the current capture. * * In this case, no sampling algorithms are applied to the current capture. */ #define PCAP_SAMP_NOSAMP 0 /* * \brief It defines that only 1 out of N packets must be returned to the user. * * In this case, the 'value' field of the 'pcap_samp' structure indicates the * number of packets (minus 1) that must be discarded before one packet got accepted. * In other words, if 'value = 10', the first packet is returned to the caller, while * the following 9 are discarded. */ #define PCAP_SAMP_1_EVERY_N 1 /* * \brief It defines that we have to return 1 packet every N milliseconds. * * In this case, the 'value' field of the 'pcap_samp' structure indicates the 'waiting * time' in milliseconds before one packet got accepted. * In other words, if 'value = 10', the first packet is returned to the caller; the next * returned one will be the first packet that arrives when 10ms have elapsed. */ #define PCAP_SAMP_FIRST_AFTER_N_MS 2 /* * \} */ /* * \addtogroup remote_auth_methods * \{ */ /* * \brief It defines the NULL authentication. * * This value has to be used within the 'type' member of the pcap_rmtauth structure. * The 'NULL' authentication has to be equal to 'zero', so that old applications * can just put every field of struct pcap_rmtauth to zero, and it does work. */ #define RPCAP_RMTAUTH_NULL 0 /* * \brief It defines the username/password authentication. * * With this type of authentication, the RPCAP protocol will use the username/ * password provided to authenticate the user on the remote machine. If the * authentication is successful (and the user has the right to open network devices) * the RPCAP connection will continue; otherwise it will be dropped. * * This value has to be used within the 'type' member of the pcap_rmtauth structure. */ #define RPCAP_RMTAUTH_PWD 1 /* * \} */ /* * \brief This structure keeps the information needed to autheticate * the user on a remote machine. * * The remote machine can either grant or refuse the access according * to the information provided. * In case the NULL authentication is required, both 'username' and * 'password' can be NULL pointers. * * This structure is meaningless if the source is not a remote interface; * in that case, the functions which requires such a structure can accept * a NULL pointer as well. */ struct pcap_rmtauth { /* * \brief Type of the authentication required. * * In order to provide maximum flexibility, we can support different types * of authentication based on the value of this 'type' variable. The currently * supported authentication methods are defined into the * \link remote_auth_methods Remote Authentication Methods Section\endlink. */ int type; /* * \brief Zero-terminated string containing the username that has to be * used on the remote machine for authentication. * * This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication * and it can be NULL. */ char *username; /* * \brief Zero-terminated string containing the password that has to be * used on the remote machine for authentication. * * This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication * and it can be NULL. */ char *password; }; /* * \brief This structure defines the information related to sampling. * * In case the sampling is requested, the capturing device should read * only a subset of the packets coming from the source. The returned packets depend * on the sampling parameters. * * \warning The sampling process is applied after the filtering process. * In other words, packets are filtered first, then the sampling process selects a * subset of the 'filtered' packets and it returns them to the caller. */ struct pcap_samp { /* * Method used for sampling. Currently, the supported methods are listed in the * \link remote_samp_methods Sampling Methods Section\endlink. */ int method; /* * This value depends on the sampling method defined. For its meaning, please check * at the \link remote_samp_methods Sampling Methods Section\endlink. */ int value; }; // Maximum length of an host name (needed for the RPCAP active mode) #define RPCAP_HOSTLIST_SIZE 1024 /* * \} */ // end of public documentation // Exported functions /* * \name New WinPcap functions * * This section lists the new functions that are able to help considerably in writing * WinPcap programs because of their easiness of use. */ // \{ PCAP_API pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf); PCAP_API int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf); PCAP_API int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf); PCAP_API int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); PCAP_API struct pcap_samp *pcap_setsampling(pcap_t *p); // \} // End of new WinPcap functions /* * \name Remote Capture functions */ /* * Some minor differences between UN*X sockets and and Winsock sockets. */ #ifndef _WIN32 /*! * \brief In Winsock, a socket handle is of type SOCKET; in UN*X, it's * a file descriptor, and therefore a signed integer. * We define SOCKET to be a signed integer on UN*X, so that it can * be used on both platforms. */ #define SOCKET int /*! * \brief In Winsock, the error return if socket() fails is INVALID_SOCKET; * in UN*X, it's -1. * We define INVALID_SOCKET to be -1 on UN*X, so that it can be used on * both platforms. */ #define INVALID_SOCKET -1 #endif // \{ PCAP_API SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf); PCAP_API int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf); PCAP_API int pcap_remoteact_close(const char *host, char *errbuf); PCAP_API void pcap_remoteact_cleanup(); // \} // End of remote capture functions #ifdef __cplusplus } #endif #endif libpcap-1.8.1/sockutils.h0000644000026300017510000001742613003771737013471 0ustar mcrmcr/* * Copyright (c) 2002 - 2003 * NetGroup, Politecnico di Torino (Italy) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __SOCKUTILS_H__ #define __SOCKUTILS_H__ #if _MSC_VER > 1000 #pragma once #endif #ifdef _WIN32 /* Windows */ /* * Prevents a compiler warning in case this was already defined (to * avoid that windows.h includes winsock.h) */ #ifdef _WINSOCKAPI_ #undef _WINSOCKAPI_ #endif /* Need windef.h for defines used in winsock2.h under MingW32 */ #ifdef __MINGW32__ #include #endif #include #include #else /* UN*X */ #include #include /* for memset() */ #include #include #include /* DNS lookup */ #include /* close() */ #include /* errno() */ #include /* for sockaddr_in, in BSD at least */ #include #include /*! * \brief In Winsock, a socket handle is of type SOCKET; in UN*X, it's * a file descriptor, and therefore a signed integer. * We define SOCKET to be a signed integer on UN*X, so that it can * be used on both platforms. */ #ifndef SOCKET #define SOCKET int #endif /*! * \brief In Winsock, the error return if socket() fails is INVALID_SOCKET; * in UN*X, it's -1. * We define INVALID_SOCKET to be -1 on UN*X, so that it can be used on * both platforms. */ #ifndef INVALID_SOCKET #define INVALID_SOCKET -1 #endif #endif /* * MingW headers include this definition, but only for Windows XP and above. * MSDN states that this function is available for most versions on Windows. */ #if ((defined(__MINGW32__)) && (_WIN32_WINNT < 0x0501)) int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD, char*,DWORD,int); #endif /* * \defgroup SockUtils Cross-platform socket utilities (IPv4-IPv6) */ /* * \addtogroup SockUtils * \{ */ /* * \defgroup ExportedStruct Exported Structures and Definitions */ /* * \addtogroup ExportedStruct * \{ */ /* * Some minor differences between UN*X sockets and and Winsock sockets. */ #ifdef _WIN32 /* * Winsock doesn't have these UN*X types; they're used in the UN*X * sockets API. * * XXX - do we need to worry about UN*Xes so old that *they* don't * have them, either? */ typedef int socklen_t; #else /*! * \brief In Winsock, the close() call cannot be used on a socket; * closesocket() must be used. * We define closesocket() to be a wrapper around close() on UN*X, * so that it can be used on both platforms. */ #define closesocket(a) close(a) #endif /* * \brief DEBUG facility: it prints an error message on the screen (stderr) * * This macro prints the error on the standard error stream (stderr); * if we are working in debug mode (i.e. there is no NDEBUG defined) and we are in * Microsoft Visual C++, the error message will appear on the MSVC console as well. * * When NDEBUG is defined, this macro is empty. * * \param msg: the message you want to print. * * \param expr: 'false' if you want to abort the program, 'true' it you want * to print the message and continue. * * \return No return values. */ #ifdef NDEBUG #define SOCK_ASSERT(msg, expr) ((void)0) #else #include #if (defined(_WIN32) && defined(_MSC_VER)) #include /* for _CrtDbgReport */ /* Use MessageBox(NULL, msg, "warning", MB_OK)' instead of the other calls if you want to debug a Win32 service */ /* Remember to activate the 'allow service to interact with desktop' flag of the service */ #define SOCK_ASSERT(msg, expr) { _CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "%s\n", msg); fprintf(stderr, "%s\n", msg); assert(expr); } #else #define SOCK_ASSERT(msg, expr) { fprintf(stderr, "%s\n", msg); assert(expr); } #endif #endif /**************************************************** * * * Exported functions / definitions * * * ****************************************************/ /* 'checkonly' flag, into the rpsock_bufferize() */ #define SOCKBUF_CHECKONLY 1 /* no 'checkonly' flag, into the rpsock_bufferize() */ #define SOCKBUF_BUFFERIZE 0 /* no 'server' flag; it opens a client socket */ #define SOCKOPEN_CLIENT 0 /* 'server' flag; it opens a server socket */ #define SOCKOPEN_SERVER 1 /* Changes the behaviour of the sock_recv(); it does not wait to receive all data */ #define SOCK_RECEIVEALL_NO 0 /* Changes the behaviour of the sock_recv(); it waits to receive all data */ #define SOCK_RECEIVEALL_YES 1 /* * \} */ #ifdef __cplusplus extern "C" { #endif /* * \defgroup ExportedFunc Exported Functions */ /* * \addtogroup ExportedFunc * \{ */ int sock_init(char *errbuf, int errbuflen); void sock_cleanup(void); /* It is 'public' because there are calls (like accept() ) which are not managed from inside the sockutils files */ void sock_geterror(const char *caller, char *errbuf, int errbufsize); int sock_initaddress(const char *address, const char *port, struct addrinfo *hints, struct addrinfo **addrinfo, char *errbuf, int errbuflen); int sock_recv(SOCKET socket, void *buffer, size_t size, int receiveall, char *errbuf, int errbuflen); SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen); int sock_close(SOCKET sock, char *errbuf, int errbuflen); int sock_send(SOCKET socket, const char *buffer, int size, char *errbuf, int errbuflen); int sock_bufferize(const char *buffer, int size, char *tempbuf, int *offset, int totsize, int checkonly, char *errbuf, int errbuflen); int sock_discard(SOCKET socket, int size, char *errbuf, int errbuflen); int sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage *from, char *errbuf, int errbuflen); int sock_cmpaddr(struct sockaddr_storage *first, struct sockaddr_storage *second); int sock_getmyinfo(SOCKET sock, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen); int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen); int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, int addr_family, char *errbuf, int errbuflen); #ifdef __cplusplus } #endif /* * \} */ /* * \} */ #endif libpcap-1.8.1/pcap-snoop.c0000644000026300017510000003115013003771737013511 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcap-int.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif /* * Private data for capturing on snoop devices. */ struct pcap_snoop { struct pcap_stat stat; }; static int pcap_read_snoop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct pcap_snoop *psn = p->priv; int cc; register struct snoopheader *sh; register u_int datalen; register u_int caplen; register u_char *cp; again: /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that it * has, and return -2 to indicate that we were * told to break out of the loop. */ p->break_loop = 0; return (-2); } cc = read(p->fd, (char *)p->buffer, p->bufsize); if (cc < 0) { /* Don't choke when we get ptraced */ switch (errno) { case EINTR: goto again; case EWOULDBLOCK: return (0); /* XXX */ } pcap_snprintf(p->errbuf, sizeof(p->errbuf), "read: %s", pcap_strerror(errno)); return (-1); } sh = (struct snoopheader *)p->buffer; datalen = sh->snoop_packetlen; /* * XXX - Sigh, snoop_packetlen is a 16 bit quantity. If we * got a short length, but read a full sized snoop pakcet, * assume we overflowed and add back the 64K... */ if (cc == (p->snapshot + sizeof(struct snoopheader)) && (datalen < p->snapshot)) datalen += (64 * 1024); caplen = (datalen < p->snapshot) ? datalen : p->snapshot; cp = (u_char *)(sh + 1) + p->offset; /* XXX */ /* * XXX unfortunately snoop loopback isn't exactly like * BSD's. The address family is encoded in the first 2 * bytes rather than the first 4 bytes! Luckily the last * two snoop loopback bytes are zeroed. */ if (p->linktype == DLT_NULL && *((short *)(cp + 2)) == 0) { u_int *uip = (u_int *)cp; *uip >>= 16; } if (p->fcode.bf_insns == NULL || bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) { struct pcap_pkthdr h; ++psn->stat.ps_recv; h.ts.tv_sec = sh->snoop_timestamp.tv_sec; h.ts.tv_usec = sh->snoop_timestamp.tv_usec; h.len = datalen; h.caplen = caplen; (*callback)(user, &h, cp); return (1); } return (0); } static int pcap_inject_snoop(pcap_t *p, const void *buf, size_t size) { int ret; /* * XXX - libnet overwrites the source address with what I * presume is the interface's address; is that required? */ ret = write(p->fd, buf, size); if (ret == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", pcap_strerror(errno)); return (-1); } return (ret); } static int pcap_stats_snoop(pcap_t *p, struct pcap_stat *ps) { struct pcap_snoop *psn = p->priv; register struct rawstats *rs; struct rawstats rawstats; rs = &rawstats; memset(rs, 0, sizeof(*rs)); if (ioctl(p->fd, SIOCRAWSTATS, (char *)rs) < 0) { pcap_snprintf(p->errbuf, sizeof(p->errbuf), "SIOCRAWSTATS: %s", pcap_strerror(errno)); return (-1); } /* * "ifdrops" are those dropped by the network interface * due to resource shortages or hardware errors. * * "sbdrops" are those dropped due to socket buffer limits. * * As filter is done in userland, "sbdrops" counts packets * regardless of whether they would've passed the filter. * * XXX - does this count *all* Snoop or Drain sockets, * rather than just this socket? If not, why does it have * both Snoop and Drain statistics? */ psn->stat.ps_drop = rs->rs_snoop.ss_ifdrops + rs->rs_snoop.ss_sbdrops + rs->rs_drain.ds_ifdrops + rs->rs_drain.ds_sbdrops; /* * "ps_recv" counts only packets that passed the filter. * As filtering is done in userland, this does not include * packets dropped because we ran out of buffer space. */ *ps = psn->stat; return (0); } /* XXX can't disable promiscuous */ static int pcap_activate_snoop(pcap_t *p) { int fd; struct sockaddr_raw sr; struct snoopfilter sf; u_int v; int ll_hdrlen; int snooplen; struct ifreq ifr; fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP); if (fd < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snoop socket: %s", pcap_strerror(errno)); goto bad; } p->fd = fd; memset(&sr, 0, sizeof(sr)); sr.sr_family = AF_RAW; (void)strncpy(sr.sr_ifname, p->opt.device, sizeof(sr.sr_ifname)); if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) { /* * XXX - there's probably a particular bind error that * means "there's no such device" and a particular bind * error that means "that device doesn't support snoop"; * they might be the same error, if they both end up * meaning "snoop doesn't know about that device". */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snoop bind: %s", pcap_strerror(errno)); goto bad; } memset(&sf, 0, sizeof(sf)); if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCADDSNOOP: %s", pcap_strerror(errno)); goto bad; } if (p->opt.buffer_size != 0) v = p->opt.buffer_size; else v = 64 * 1024; /* default to 64K buffer size */ (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v)); /* * XXX hack - map device name to link layer type */ if (strncmp("et", p->opt.device, 2) == 0 || /* Challenge 10 Mbit */ strncmp("ec", p->opt.device, 2) == 0 || /* Indigo/Indy 10 Mbit, O2 10/100 */ strncmp("ef", p->opt.device, 2) == 0 || /* O200/2000 10/100 Mbit */ strncmp("eg", p->opt.device, 2) == 0 || /* Octane/O2xxx/O3xxx Gigabit */ strncmp("gfe", p->opt.device, 3) == 0 || /* GIO 100 Mbit */ strncmp("fxp", p->opt.device, 3) == 0 || /* Challenge VME Enet */ strncmp("ep", p->opt.device, 2) == 0 || /* Challenge 8x10 Mbit EPLEX */ strncmp("vfe", p->opt.device, 3) == 0 || /* Challenge VME 100Mbit */ strncmp("fa", p->opt.device, 2) == 0 || strncmp("qaa", p->opt.device, 3) == 0 || strncmp("cip", p->opt.device, 3) == 0 || strncmp("el", p->opt.device, 2) == 0) { p->linktype = DLT_EN10MB; p->offset = RAW_HDRPAD(sizeof(struct ether_header)); ll_hdrlen = sizeof(struct ether_header); /* * This is (presumably) a real Ethernet capture; give it a * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so * that an application can let you choose it, in case you're * capturing DOCSIS traffic that a Cisco Cable Modem * Termination System is putting out onto an Ethernet (it * doesn't put an Ethernet header onto the wire, it puts raw * DOCSIS frames out on the wire inside the low-level * Ethernet framing). * * XXX - are there any sorts of "fake Ethernet" that have * Ethernet link-layer headers but that *shouldn't offer * DLT_DOCSIS as a Cisco CMTS won't put traffic onto it * or get traffic bridged onto it? "el" is for ATM LANE * Ethernet devices, so that might be the case for them; * the same applies for "qaa" classical IP devices. If * "fa" devices are for FORE SPANS, that'd apply to them * as well; what are "cip" devices - some other ATM * Classical IP devices? */ p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (p->dlt_list != NULL) { p->dlt_list[0] = DLT_EN10MB; p->dlt_list[1] = DLT_DOCSIS; p->dlt_count = 2; } } else if (strncmp("ipg", p->opt.device, 3) == 0 || strncmp("rns", p->opt.device, 3) == 0 || /* O2/200/2000 FDDI */ strncmp("xpi", p->opt.device, 3) == 0) { p->linktype = DLT_FDDI; p->offset = 3; /* XXX yeah? */ ll_hdrlen = 13; } else if (strncmp("ppp", p->opt.device, 3) == 0) { p->linktype = DLT_RAW; ll_hdrlen = 0; /* DLT_RAW meaning "no PPP header, just the IP packet"? */ } else if (strncmp("qfa", p->opt.device, 3) == 0) { p->linktype = DLT_IP_OVER_FC; ll_hdrlen = 24; } else if (strncmp("pl", p->opt.device, 2) == 0) { p->linktype = DLT_RAW; ll_hdrlen = 0; /* Cray UNICOS/mp pseudo link */ } else if (strncmp("lo", p->opt.device, 2) == 0) { p->linktype = DLT_NULL; ll_hdrlen = 4; } else { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snoop: unknown physical layer type"); goto bad; } if (p->opt.rfmon) { /* * No monitor mode on Irix (no Wi-Fi devices on * hardware supported by Irix). */ return (PCAP_ERROR_RFMON_NOTSUP); } #ifdef SIOCGIFMTU /* * XXX - IRIX appears to give you an error if you try to set the * capture length to be greater than the MTU, so let's try to get * the MTU first and, if that succeeds, trim the snap length * to be no greater than the MTU. */ (void)strncpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMTU: %s", pcap_strerror(errno)); goto bad; } /* * OK, we got it. * * XXX - some versions of IRIX 6.5 define "ifr_mtu" and have an * "ifru_metric" member of the "ifr_ifru" union in an "ifreq" * structure, others don't. * * I've no idea what's going on, so, if "ifr_mtu" isn't defined, * we define it as "ifr_metric", as using that field appears to * work on the versions that lack "ifr_mtu" (and, on those that * don't lack it, "ifru_metric" and "ifru_mtu" are both "int" * members of the "ifr_ifru" union, which suggests that they * may be interchangeable in this case). */ #ifndef ifr_mtu #define ifr_mtu ifr_metric #endif if (p->snapshot > ifr.ifr_mtu + ll_hdrlen) p->snapshot = ifr.ifr_mtu + ll_hdrlen; #endif /* * The argument to SIOCSNOOPLEN is the number of link-layer * payload bytes to capture - it doesn't count link-layer * header bytes. */ snooplen = p->snapshot - ll_hdrlen; if (snooplen < 0) snooplen = 0; if (ioctl(fd, SIOCSNOOPLEN, &snooplen) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPLEN: %s", pcap_strerror(errno)); goto bad; } v = 1; if (ioctl(fd, SIOCSNOOPING, &v) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPING: %s", pcap_strerror(errno)); goto bad; } p->bufsize = 4096; /* XXX */ p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); goto bad; } /* * "p->fd" is a socket, so "select()" should work on it. */ p->selectable_fd = p->fd; p->read_op = pcap_read_snoop; p->inject_op = pcap_inject_snoop; p->setfilter_op = install_bpf_program; /* no kernel filtering */ p->setdirection_op = NULL; /* Not implemented. */ p->set_datalink_op = NULL; /* can't change data link type */ p->getnonblock_op = pcap_getnonblock_fd; p->setnonblock_op = pcap_setnonblock_fd; p->stats_op = pcap_stats_snoop; return (0); bad: pcap_cleanup_live_common(p); return (PCAP_ERROR); } pcap_t * pcap_create_interface(const char *device _U_, char *ebuf) { pcap_t *p; p = pcap_create_common(ebuf, sizeof (struct pcap_snoop)); if (p == NULL) return (NULL); p->activate_op = pcap_activate_snoop; return (p); } /* * XXX - there's probably a particular bind error that means "that device * doesn't support snoop"; if so, we should try a bind and use that. */ static int can_be_bound(const char *name _U_) { return (1); } int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { return (pcap_findalldevs_interfaces(alldevsp, errbuf, can_be_bound)); } libpcap-1.8.1/pcap_major_version.3pcap0000644000026300017510000000372213003771737016102 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_MAJOR_VERSION 3PCAP "7 April 2014" .SH NAME pcap_major_version, pcap_minor_version \- get the version number of a savefile .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_major_version(pcap_t *p); int pcap_minor_version(pcap_t *p); .ft .fi .SH DESCRIPTION If .I p refers to a ``savefile'', .B pcap_major_version() returns the major number of the file format of the ``savefile'' and .B pcap_minor_version() returns the minor number of the file format of the ``savefile''. The version number is stored in the ``savefile''; note that the meaning of its values depends on the type of ``savefile'' (for example, pcap or pcap-NG). .PP If .I p refers to a live capture, the values returned by .B pcap_major_version() and .B pcap_minor_version() are not meaningful. .SH SEE ALSO pcap(3PCAP) libpcap-1.8.1/pcap-filter.manmisc.in0000644000026300017510000007775213003771737015474 0ustar mcrmcr.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" 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. .\" .TH PCAP-FILTER @MAN_MISC_INFO@ "3 August 2015" .SH NAME pcap-filter \- packet filter syntax .br .ad .SH DESCRIPTION .LP .B pcap_compile() is used to compile a string into a filter program. The resulting filter program can then be applied to some stream of packets to determine which packets will be supplied to .BR pcap_loop() , .BR pcap_dispatch() , .BR pcap_next() , or .BR pcap_next_ex() . .LP The \fIfilter expression\fP consists of one or more .IR primitives . Primitives usually consist of an .I id (name or number) preceded by one or more qualifiers. There are three different kinds of qualifier: .IP \fItype\fP .I type qualifiers say what kind of thing the id name or number refers to. Possible types are .BR host , .B net , .B port and .BR portrange . E.g., `host foo', `net 128.3', `port 20', `portrange 6000-6008'. If there is no type qualifier, .B host is assumed. .IP \fIdir\fP .I dir qualifiers specify a particular transfer direction to and/or from .IR id . Possible directions are .BR src , .BR dst , .BR "src or dst" , .BR "src and dst" , .BR ra , .BR ta , .BR addr1 , .BR addr2 , .BR addr3 , and .BR addr4 . E.g., `src foo', `dst net 128.3', `src or dst port ftp-data'. If there is no dir qualifier, .B "src or dst" is assumed. The .BR ra , .BR ta , .BR addr1 , .BR addr2 , .BR addr3 , and .B addr4 qualifiers are only valid for IEEE 802.11 Wireless LAN link layers. For some link layers, such as SLIP and the ``cooked'' Linux capture mode used for the ``any'' device and for some other device types, the .B inbound and .B outbound qualifiers can be used to specify a desired direction. .IP \fIproto\fP .I proto qualifiers restrict the match to a particular protocol. Possible protos are: .BR ether , .BR fddi , .BR tr , .BR wlan , .BR ip , .BR ip6 , .BR arp , .BR rarp , .BR decnet , .B tcp and .BR udp . E.g., `ether src foo', `arp net 128.3', `tcp port 21', `udp portrange 7000-7009', `wlan addr2 0:2:3:4:5:6'. If there is no proto qualifier, all protocols consistent with the type are assumed. E.g., `src foo' means `(ip or arp or rarp) src foo' (except the latter is not legal syntax), `net bar' means `(ip or arp or rarp) net bar' and `port 53' means `(tcp or udp) port 53'. .LP [`fddi' is actually an alias for `ether'; the parser treats them identically as meaning ``the data link level used on the specified network interface.'' FDDI headers contain Ethernet-like source and destination addresses, and often contain Ethernet-like packet types, so you can filter on these FDDI fields just as with the analogous Ethernet fields. FDDI headers also contain other fields, but you cannot name them explicitly in a filter expression. .LP Similarly, `tr' and `wlan' are aliases for `ether'; the previous paragraph's statements about FDDI headers also apply to Token Ring and 802.11 wireless LAN headers. For 802.11 headers, the destination address is the DA field and the source address is the SA field; the BSSID, RA, and TA fields aren't tested.] .LP In addition to the above, there are some special `primitive' keywords that don't follow the pattern: .BR gateway , .BR broadcast , .BR less , .B greater and arithmetic expressions. All of these are described below. .LP More complex filter expressions are built up by using the words .BR and , .B or and .B not to combine primitives. E.g., `host foo and not port ftp and not port ftp-data'. To save typing, identical qualifier lists can be omitted. E.g., `tcp dst port ftp or ftp-data or domain' is exactly the same as `tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain'. .LP Allowable primitives are: .IP "\fBdst host \fIhost\fR" True if the IPv4/v6 destination field of the packet is \fIhost\fP, which may be either an address or a name. .IP "\fBsrc host \fIhost\fR" True if the IPv4/v6 source field of the packet is \fIhost\fP. .IP "\fBhost \fIhost\fP" True if either the IPv4/v6 source or destination of the packet is \fIhost\fP. .IP Any of the above host expressions can be prepended with the keywords, \fBip\fP, \fBarp\fP, \fBrarp\fP, or \fBip6\fP as in: .in +.5i .nf \fBip host \fIhost\fR .fi .in -.5i which is equivalent to: .in +.5i .nf \fBether proto \fI\\ip\fB and host \fIhost\fR .fi .in -.5i If \fIhost\fR is a name with multiple IP addresses, each address will be checked for a match. .IP "\fBether dst \fIehost\fP" True if the Ethernet destination address is \fIehost\fP. \fIEhost\fP may be either a name from /etc/ethers or a number (see .IR ethers (3N) for numeric format). .IP "\fBether src \fIehost\fP" True if the Ethernet source address is \fIehost\fP. .IP "\fBether host \fIehost\fP" True if either the Ethernet source or destination address is \fIehost\fP. .IP "\fBgateway\fP \fIhost\fP" True if the packet used \fIhost\fP as a gateway. I.e., the Ethernet source or destination address was \fIhost\fP but neither the IP source nor the IP destination was \fIhost\fP. \fIHost\fP must be a name and must be found both by the machine's host-name-to-IP-address resolution mechanisms (host name file, DNS, NIS, etc.) and by the machine's host-name-to-Ethernet-address resolution mechanism (/etc/ethers, etc.). (An equivalent expression is .in +.5i .nf \fBether host \fIehost \fBand not host \fIhost\fR .fi .in -.5i which can be used with either names or numbers for \fIhost / ehost\fP.) This syntax does not work in IPv6-enabled configuration at this moment. .IP "\fBdst net \fInet\fR" True if the IPv4/v6 destination address of the packet has a network number of \fInet\fP. \fINet\fP may be either a name from the networks database (/etc/networks, etc.) or a network number. An IPv4 network number can be written as a dotted quad (e.g., 192.168.1.0), dotted triple (e.g., 192.168.1), dotted pair (e.g, 172.16), or single number (e.g., 10); the netmask is 255.255.255.255 for a dotted quad (which means that it's really a host match), 255.255.255.0 for a dotted triple, 255.255.0.0 for a dotted pair, or 255.0.0.0 for a single number. An IPv6 network number must be written out fully; the netmask is ff:ff:ff:ff:ff:ff:ff:ff, so IPv6 "network" matches are really always host matches, and a network match requires a netmask length. .IP "\fBsrc net \fInet\fR" True if the IPv4/v6 source address of the packet has a network number of \fInet\fP. .IP "\fBnet \fInet\fR" True if either the IPv4/v6 source or destination address of the packet has a network number of \fInet\fP. .IP "\fBnet \fInet\fR \fBmask \fInetmask\fR" True if the IPv4 address matches \fInet\fR with the specific \fInetmask\fR. May be qualified with \fBsrc\fR or \fBdst\fR. Note that this syntax is not valid for IPv6 \fInet\fR. .IP "\fBnet \fInet\fR/\fIlen\fR" True if the IPv4/v6 address matches \fInet\fR with a netmask \fIlen\fR bits wide. May be qualified with \fBsrc\fR or \fBdst\fR. .IP "\fBdst port \fIport\fR" True if the packet is ip/tcp, ip/udp, ip6/tcp or ip6/udp and has a destination port value of \fIport\fP. The \fIport\fP can be a number or a name used in /etc/services (see .IR tcp (4P) and .IR udp (4P)). If a name is used, both the port number and protocol are checked. If a number or ambiguous name is used, only the port number is checked (e.g., \fBdst port 513\fR will print both tcp/login traffic and udp/who traffic, and \fBport domain\fR will print both tcp/domain and udp/domain traffic). .IP "\fBsrc port \fIport\fR" True if the packet has a source port value of \fIport\fP. .IP "\fBport \fIport\fR" True if either the source or destination port of the packet is \fIport\fP. .IP "\fBdst portrange \fIport1\fB-\fIport2\fR" True if the packet is ip/tcp, ip/udp, ip6/tcp or ip6/udp and has a destination port value between \fIport1\fP and \fIport2\fP. .I port1 and .I port2 are interpreted in the same fashion as the .I port parameter for .BR port . .IP "\fBsrc portrange \fIport1\fB-\fIport2\fR" True if the packet has a source port value between \fIport1\fP and \fIport2\fP. .IP "\fBportrange \fIport1\fB-\fIport2\fR" True if either the source or destination port of the packet is between \fIport1\fP and \fIport2\fP. .IP Any of the above port or port range expressions can be prepended with the keywords, \fBtcp\fP or \fBudp\fP, as in: .in +.5i .nf \fBtcp src port \fIport\fR .fi .in -.5i which matches only tcp packets whose source port is \fIport\fP. .IP "\fBless \fIlength\fR" True if the packet has a length less than or equal to \fIlength\fP. This is equivalent to: .in +.5i .nf \fBlen <= \fIlength\fP. .fi .in -.5i .IP "\fBgreater \fIlength\fR" True if the packet has a length greater than or equal to \fIlength\fP. This is equivalent to: .in +.5i .nf \fBlen >= \fIlength\fP. .fi .in -.5i .IP "\fBip proto \fIprotocol\fR" True if the packet is an IPv4 packet (see .IR ip (4P)) of protocol type \fIprotocol\fP. \fIProtocol\fP can be a number or one of the names \fBicmp\fP, \fBicmp6\fP, \fBigmp\fP, \fBigrp\fP, \fBpim\fP, \fBah\fP, \fBesp\fP, \fBvrrp\fP, \fBudp\fP, or \fBtcp\fP. Note that the identifiers \fBtcp\fP, \fBudp\fP, and \fBicmp\fP are also keywords and must be escaped via backslash (\\). Note that this primitive does not chase the protocol header chain. .IP "\fBip6 proto \fIprotocol\fR" True if the packet is an IPv6 packet of protocol type \fIprotocol\fP. Note that this primitive does not chase the protocol header chain. .IP "\fBproto \fIprotocol\fR" True if the packet is an IPv4 or IPv6 packet of protocol type \fIprotocol\fP. Note that this primitive does not chase the protocol header chain. .IP "\fBtcp\fR, \fBudp\fR, \fBicmp\fR" Abbreviations for: .in +.5i .nf \fBproto \fIp\fR\fB .fi .in -.5i where \fIp\fR is one of the above protocols. .IP "\fBip6 protochain \fIprotocol\fR" True if the packet is IPv6 packet, and contains protocol header with type \fIprotocol\fR in its protocol header chain. For example, .in +.5i .nf \fBip6 protochain 6\fR .fi .in -.5i matches any IPv6 packet with TCP protocol header in the protocol header chain. The packet may contain, for example, authentication header, routing header, or hop-by-hop option header, between IPv6 header and TCP header. The BPF code emitted by this primitive is complex and cannot be optimized by the BPF optimizer code, and is not supported by filter engines in the kernel, so this can be somewhat slow, and may cause more packets to be dropped. .IP "\fBip protochain \fIprotocol\fR" Equivalent to \fBip6 protochain \fIprotocol\fR, but this is for IPv4. .IP "\fBprotochain \fIprotocol\fR" True if the packet is an IPv4 or IPv6 packet of protocol type \fIprotocol\fP. Note that this primitive chases the protocol header chain. .IP "\fBether broadcast\fR" True if the packet is an Ethernet broadcast packet. The \fIether\fP keyword is optional. .IP "\fBip broadcast\fR" True if the packet is an IPv4 broadcast packet. It checks for both the all-zeroes and all-ones broadcast conventions, and looks up the subnet mask on the interface on which the capture is being done. .IP If the subnet mask of the interface on which the capture is being done is not available, either because the interface on which capture is being done has no netmask or because the capture is being done on the Linux "any" interface, which can capture on more than one interface, this check will not work correctly. .IP "\fBether multicast\fR" True if the packet is an Ethernet multicast packet. The \fBether\fP keyword is optional. This is shorthand for `\fBether[0] & 1 != 0\fP'. .IP "\fBip multicast\fR" True if the packet is an IPv4 multicast packet. .IP "\fBip6 multicast\fR" True if the packet is an IPv6 multicast packet. .IP "\fBether proto \fIprotocol\fR" True if the packet is of ether type \fIprotocol\fR. \fIProtocol\fP can be a number or one of the names \fBip\fP, \fBip6\fP, \fBarp\fP, \fBrarp\fP, \fBatalk\fP, \fBaarp\fP, \fBdecnet\fP, \fBsca\fP, \fBlat\fP, \fBmopdl\fP, \fBmoprc\fP, \fBiso\fP, \fBstp\fP, \fBipx\fP, or \fBnetbeui\fP. Note these identifiers are also keywords and must be escaped via backslash (\\). .IP [In the case of FDDI (e.g., `\fBfddi proto arp\fR'), Token Ring (e.g., `\fBtr proto arp\fR'), and IEEE 802.11 wireless LANS (e.g., `\fBwlan proto arp\fR'), for most of those protocols, the protocol identification comes from the 802.2 Logical Link Control (LLC) header, which is usually layered on top of the FDDI, Token Ring, or 802.11 header. .IP When filtering for most protocol identifiers on FDDI, Token Ring, or 802.11, the filter checks only the protocol ID field of an LLC header in so-called SNAP format with an Organizational Unit Identifier (OUI) of 0x000000, for encapsulated Ethernet; it doesn't check whether the packet is in SNAP format with an OUI of 0x000000. The exceptions are: .RS .TP \fBiso\fP the filter checks the DSAP (Destination Service Access Point) and SSAP (Source Service Access Point) fields of the LLC header; .TP \fBstp\fP and \fBnetbeui\fP the filter checks the DSAP of the LLC header; .TP \fBatalk\fP the filter checks for a SNAP-format packet with an OUI of 0x080007 and the AppleTalk etype. .RE .IP In the case of Ethernet, the filter checks the Ethernet type field for most of those protocols. The exceptions are: .RS .TP \fBiso\fP, \fBstp\fP, and \fBnetbeui\fP the filter checks for an 802.3 frame and then checks the LLC header as it does for FDDI, Token Ring, and 802.11; .TP \fBatalk\fP the filter checks both for the AppleTalk etype in an Ethernet frame and for a SNAP-format packet as it does for FDDI, Token Ring, and 802.11; .TP \fBaarp\fP the filter checks for the AppleTalk ARP etype in either an Ethernet frame or an 802.2 SNAP frame with an OUI of 0x000000; .TP \fBipx\fP the filter checks for the IPX etype in an Ethernet frame, the IPX DSAP in the LLC header, the 802.3-with-no-LLC-header encapsulation of IPX, and the IPX etype in a SNAP frame. .RE .IP "\fBip\fR, \fBip6\fR, \fBarp\fR, \fBrarp\fR, \fBatalk\fR, \fBaarp\fR, \fBdecnet\fR, \fBiso\fR, \fBstp\fR, \fBipx\fR, \fBnetbeui\fP" Abbreviations for: .in +.5i .nf \fBether proto \fIp\fR .fi .in -.5i where \fIp\fR is one of the above protocols. .IP "\fBlat\fR, \fBmoprc\fR, \fBmopdl\fR" Abbreviations for: .in +.5i .nf \fBether proto \fIp\fR .fi .in -.5i where \fIp\fR is one of the above protocols. Note that not all applications using .BR pcap (3PCAP) currently know how to parse these protocols. .IP "\fBdecnet src \fIhost\fR" True if the DECNET source address is .IR host , which may be an address of the form ``10.123'', or a DECNET host name. [DECNET host name support is only available on ULTRIX systems that are configured to run DECNET.] .IP "\fBdecnet dst \fIhost\fR" True if the DECNET destination address is .IR host . .IP "\fBdecnet host \fIhost\fR" True if either the DECNET source or destination address is .IR host . .IP \fBllc\fP True if the packet has an 802.2 LLC header. This includes: .IP Ethernet packets with a length field rather than a type field that aren't raw NetWare-over-802.3 packets; .IP IEEE 802.11 data packets; .IP Token Ring packets (no check is done for LLC frames); .IP FDDI packets (no check is done for LLC frames); .IP LLC-encapsulated ATM packets, for SunATM on Solaris. .IP .IP "\fBllc\fP \Fitype\fR" True if the packet has an 802.2 LLC header and has the specified .IR type . .I type can be one of: .RS .TP \fBi\fR Information (I) PDUs .TP \fBs\fR Supervisory (S) PDUs .TP \fBu\fR Unnumbered (U) PDUs .TP \fBrr\fR Receiver Ready (RR) S PDUs .TP \fBrnr\fR Receiver Not Ready (RNR) S PDUs .TP \fBrej\fR Reject (REJ) S PDUs .TP \fBui\fR Unnumbered Information (UI) U PDUs .TP \fBua\fR Unnumbered Acknowledgment (UA) U PDUs .TP \fBdisc\fR Disconnect (DISC) U PDUs .TP \fBsabme\fR Set Asynchronous Balanced Mode Extended (SABME) U PDUs .TP \fBtest\fR Test (TEST) U PDUs .TP \fBxid\fR Exchange Identification (XID) U PDUs .TP \fBfrmr\fR Frame Reject (FRMR) U PDUs .RE .IP "\fBifname \fIinterface\fR" True if the packet was logged as coming from the specified interface (applies only to packets logged by OpenBSD's or FreeBSD's .BR pf (4)). .IP "\fBon \fIinterface\fR" Synonymous with the .B ifname modifier. .IP "\fBrnr \fInum\fR" True if the packet was logged as matching the specified PF rule number (applies only to packets logged by OpenBSD's or FreeBSD's .BR pf (4)). .IP "\fBrulenum \fInum\fR" Synonymous with the .B rnr modifier. .IP "\fBreason \fIcode\fR" True if the packet was logged with the specified PF reason code. The known codes are: .BR match , .BR bad-offset , .BR fragment , .BR short , .BR normalize , and .B memory (applies only to packets logged by OpenBSD's or FreeBSD's .BR pf (4)). .IP "\fBrset \fIname\fR" True if the packet was logged as matching the specified PF ruleset name of an anchored ruleset (applies only to packets logged by OpenBSD's or FreeBSD's .BR pf (4)). .IP "\fBruleset \fIname\fR" Synonymous with the .B rset modifier. .IP "\fBsrnr \fInum\fR" True if the packet was logged as matching the specified PF rule number of an anchored ruleset (applies only to packets logged by OpenBSD's or FreeBSD's .BR pf (4)). .IP "\fBsubrulenum \fInum\fR" Synonymous with the .B srnr modifier. .IP "\fBaction \fIact\fR" True if PF took the specified action when the packet was logged. Known actions are: .B pass and .B block and, with later versions of .BR pf (4)), .BR nat , .BR rdr , .B binat and .B scrub (applies only to packets logged by OpenBSD's or FreeBSD's .BR pf (4)). .IP "\fBwlan ra \fIehost\fR" True if the IEEE 802.11 RA is .IR ehost . The RA field is used in all frames except for management frames. .IP "\fBwlan ta \fIehost\fR" True if the IEEE 802.11 TA is .IR ehost . The TA field is used in all frames except for management frames and CTS (Clear To Send) and ACK (Acknowledgment) control frames. .IP "\fBwlan addr1 \fIehost\fR" True if the first IEEE 802.11 address is .IR ehost . .IP "\fBwlan addr2 \fIehost\fR" True if the second IEEE 802.11 address, if present, is .IR ehost . The second address field is used in all frames except for CTS (Clear To Send) and ACK (Acknowledgment) control frames. .IP "\fBwlan addr3 \fIehost\fR" True if the third IEEE 802.11 address, if present, is .IR ehost . The third address field is used in management and data frames, but not in control frames. .IP "\fBwlan addr4 \fIehost\fR" True if the fourth IEEE 802.11 address, if present, is .IR ehost . The fourth address field is only used for WDS (Wireless Distribution System) frames. .IP "\fBtype \fIwlan_type\fR" True if the IEEE 802.11 frame type matches the specified \fIwlan_type\fR. Valid \fIwlan_type\fRs are: \fBmgt\fP, \fBctl\fP and \fBdata\fP. .IP "\fBtype \fIwlan_type \fBsubtype \fIwlan_subtype\fR" True if the IEEE 802.11 frame type matches the specified \fIwlan_type\fR and frame subtype matches the specified \fIwlan_subtype\fR. .IP If the specified \fIwlan_type\fR is \fBmgt\fP, then valid \fIwlan_subtype\fRs are: \fBassoc-req\fP, \fBassoc-resp\fP, \fBreassoc-req\fP, \fBreassoc-resp\fP, \fBprobe-req\fP, \fBprobe-resp\fP, \fBbeacon\fP, \fBatim\fP, \fBdisassoc\fP, \fBauth\fP and \fBdeauth\fP. .IP If the specified \fIwlan_type\fR is \fBctl\fP, then valid \fIwlan_subtype\fRs are: \fBps-poll\fP, \fBrts\fP, \fBcts\fP, \fBack\fP, \fBcf-end\fP and \fBcf-end-ack\fP. .IP If the specified \fIwlan_type\fR is \fBdata\fP, then valid \fIwlan_subtype\fRs are: \fBdata\fP, \fBdata-cf-ack\fP, \fBdata-cf-poll\fP, \fBdata-cf-ack-poll\fP, \fBnull\fP, \fBcf-ack\fP, \fBcf-poll\fP, \fBcf-ack-poll\fP, \fBqos-data\fP, \fBqos-data-cf-ack\fP, \fBqos-data-cf-poll\fP, \fBqos-data-cf-ack-poll\fP, \fBqos\fP, \fBqos-cf-poll\fP and \fBqos-cf-ack-poll\fP. .IP "\fBsubtype \fIwlan_subtype\fR" True if the IEEE 802.11 frame subtype matches the specified \fIwlan_subtype\fR and frame has the type to which the specified \fIwlan_subtype\fR belongs. .IP "\fBdir \fIdir\fR" True if the IEEE 802.11 frame direction matches the specified .IR dir . Valid directions are: .BR nods , .BR tods , .BR fromds , .BR dstods , or a numeric value. .IP "\fBvlan \fI[vlan_id]\fR" True if the packet is an IEEE 802.1Q VLAN packet. If \fI[vlan_id]\fR is specified, only true if the packet has the specified \fIvlan_id\fR. Note that the first \fBvlan\fR keyword encountered in \fIexpression\fR changes the decoding offsets for the remainder of \fIexpression\fR on the assumption that the packet is a VLAN packet. The \fBvlan \fI[vlan_id]\fR expression may be used more than once, to filter on VLAN hierarchies. Each use of that expression increments the filter offsets by 4. .IP For example: .in +.5i .nf \fBvlan 100 && vlan 200\fR .fi .in -.5i filters on VLAN 200 encapsulated within VLAN 100, and .in +.5i .nf \fBvlan && vlan 300 && ip\fR .fi .in -.5i filters IPv4 protocols encapsulated in VLAN 300 encapsulated within any higher order VLAN. .IP "\fBmpls \fI[label_num]\fR" True if the packet is an MPLS packet. If \fI[label_num]\fR is specified, only true is the packet has the specified \fIlabel_num\fR. Note that the first \fBmpls\fR keyword encountered in \fIexpression\fR changes the decoding offsets for the remainder of \fIexpression\fR on the assumption that the packet is a MPLS-encapsulated IP packet. The \fBmpls \fI[label_num]\fR expression may be used more than once, to filter on MPLS hierarchies. Each use of that expression increments the filter offsets by 4. .IP For example: .in +.5i .nf \fBmpls 100000 && mpls 1024\fR .fi .in -.5i filters packets with an outer label of 100000 and an inner label of 1024, and .in +.5i .nf \fBmpls && mpls 1024 && host 192.9.200.1\fR .fi .in -.5i filters packets to or from 192.9.200.1 with an inner label of 1024 and any outer label. .IP \fBpppoed\fP True if the packet is a PPP-over-Ethernet Discovery packet (Ethernet type 0x8863). .IP "\fBpppoes \fI[session_id]\fR" True if the packet is a PPP-over-Ethernet Session packet (Ethernet type 0x8864). If \fI[session_id]\fR is specified, only true if the packet has the specified \fIsession_id\fR. Note that the first \fBpppoes\fR keyword encountered in \fIexpression\fR changes the decoding offsets for the remainder of \fIexpression\fR on the assumption that the packet is a PPPoE session packet. .IP For example: .in +.5i .nf \fBpppoes 0x27 && ip\fR .fi .in -.5i filters IPv4 protocols encapsulated in PPPoE session id 0x27. .IP "\fBgeneve \fI[vni]\fR" True if the packet is a Geneve packet (UDP port 6081). If \fI[vni]\fR is specified, only true if the packet has the specified \fIvni\fR. Note that when the \fBgeneve\fR keyword is encountered in \fIexpression\fR, it changes the decoding offsets for the remainder of \fIexpression\fR on the assumption that the packet is a Geneve packet. .IP For example: .in +.5i .nf \fBgeneve 0xb && ip\fR .fi .in -.5i filters IPv4 protocols encapsulated in Geneve with VNI 0xb. This will match both IP directly encapsulated in Geneve as well as IP contained inside an Ethernet frame. .IP "\fBiso proto \fIprotocol\fR" True if the packet is an OSI packet of protocol type \fIprotocol\fP. \fIProtocol\fP can be a number or one of the names \fBclnp\fP, \fBesis\fP, or \fBisis\fP. .IP "\fBclnp\fR, \fBesis\fR, \fBisis\fR" Abbreviations for: .in +.5i .nf \fBiso proto \fIp\fR .fi .in -.5i where \fIp\fR is one of the above protocols. .IP "\fBl1\fR, \fBl2\fR, \fBiih\fR, \fBlsp\fR, \fBsnp\fR, \fBcsnp\fR, \fBpsnp\fR" Abbreviations for IS-IS PDU types. .IP "\fBvpi\fP \fIn\fR" True if the packet is an ATM packet, for SunATM on Solaris, with a virtual path identifier of .IR n . .IP "\fBvci\fP \fIn\fR" True if the packet is an ATM packet, for SunATM on Solaris, with a virtual channel identifier of .IR n . .IP \fBlane\fP True if the packet is an ATM packet, for SunATM on Solaris, and is an ATM LANE packet. Note that the first \fBlane\fR keyword encountered in \fIexpression\fR changes the tests done in the remainder of \fIexpression\fR on the assumption that the packet is either a LANE emulated Ethernet packet or a LANE LE Control packet. If \fBlane\fR isn't specified, the tests are done under the assumption that the packet is an LLC-encapsulated packet. .IP \fBoamf4s\fP True if the packet is an ATM packet, for SunATM on Solaris, and is a segment OAM F4 flow cell (VPI=0 & VCI=3). .IP \fBoamf4e\fP True if the packet is an ATM packet, for SunATM on Solaris, and is an end-to-end OAM F4 flow cell (VPI=0 & VCI=4). .IP \fBoamf4\fP True if the packet is an ATM packet, for SunATM on Solaris, and is a segment or end-to-end OAM F4 flow cell (VPI=0 & (VCI=3 | VCI=4)). .IP \fBoam\fP True if the packet is an ATM packet, for SunATM on Solaris, and is a segment or end-to-end OAM F4 flow cell (VPI=0 & (VCI=3 | VCI=4)). .IP \fBmetac\fP True if the packet is an ATM packet, for SunATM on Solaris, and is on a meta signaling circuit (VPI=0 & VCI=1). .IP \fBbcc\fP True if the packet is an ATM packet, for SunATM on Solaris, and is on a broadcast signaling circuit (VPI=0 & VCI=2). .IP \fBsc\fP True if the packet is an ATM packet, for SunATM on Solaris, and is on a signaling circuit (VPI=0 & VCI=5). .IP \fBilmic\fP True if the packet is an ATM packet, for SunATM on Solaris, and is on an ILMI circuit (VPI=0 & VCI=16). .IP \fBconnectmsg\fP True if the packet is an ATM packet, for SunATM on Solaris, and is on a signaling circuit and is a Q.2931 Setup, Call Proceeding, Connect, Connect Ack, Release, or Release Done message. .IP \fBmetaconnect\fP True if the packet is an ATM packet, for SunATM on Solaris, and is on a meta signaling circuit and is a Q.2931 Setup, Call Proceeding, Connect, Release, or Release Done message. .IP "\fIexpr relop expr\fR" True if the relation holds, where \fIrelop\fR is one of >, <, >=, <=, =, !=, and \fIexpr\fR is an arithmetic expression composed of integer constants (expressed in standard C syntax), the normal binary operators [+, -, *, /, %, &, |, ^, <<, >>], a length operator, and special packet data accessors. Note that all comparisons are unsigned, so that, for example, 0x80000000 and 0xffffffff are > 0. .IP The % and ^ operators are currently only supported for filtering in the kernel on Linux with 3.7 and later kernels; on all other systems, if those operators are used, filtering will be done in user mode, which will increase the overhead of capturing packets and may cause more packets to be dropped. .IP To access data inside the packet, use the following syntax: .in +.5i .nf \fIproto\fB [ \fIexpr\fB : \fIsize\fB ]\fR .fi .in -.5i \fIProto\fR is one of \fBether, fddi, tr, wlan, ppp, slip, link, ip, arp, rarp, tcp, udp, icmp, ip6\fR or \fBradio\fR, and indicates the protocol layer for the index operation. (\fBether, fddi, wlan, tr, ppp, slip\fR and \fBlink\fR all refer to the link layer. \fBradio\fR refers to the "radio header" added to some 802.11 captures.) Note that \fItcp, udp\fR and other upper-layer protocol types only apply to IPv4, not IPv6 (this will be fixed in the future). The byte offset, relative to the indicated protocol layer, is given by \fIexpr\fR. \fISize\fR is optional and indicates the number of bytes in the field of interest; it can be either one, two, or four, and defaults to one. The length operator, indicated by the keyword \fBlen\fP, gives the length of the packet. For example, `\fBether[0] & 1 != 0\fP' catches all multicast traffic. The expression `\fBip[0] & 0xf != 5\fP' catches all IPv4 packets with options. The expression `\fBip[6:2] & 0x1fff = 0\fP' catches only unfragmented IPv4 datagrams and frag zero of fragmented IPv4 datagrams. This check is implicitly applied to the \fBtcp\fP and \fBudp\fP index operations. For instance, \fBtcp[0]\fP always means the first byte of the TCP \fIheader\fP, and never means the first byte of an intervening fragment. Some offsets and field values may be expressed as names rather than as numeric values. The following protocol header field offsets are available: \fBicmptype\fP (ICMP type field), \fBicmpcode\fP (ICMP code field), and \fBtcpflags\fP (TCP flags field). The following ICMP type field values are available: \fBicmp-echoreply\fP, \fBicmp-unreach\fP, \fBicmp-sourcequench\fP, \fBicmp-redirect\fP, \fBicmp-echo\fP, \fBicmp-routeradvert\fP, \fBicmp-routersolicit\fP, \fBicmp-timxceed\fP, \fBicmp-paramprob\fP, \fBicmp-tstamp\fP, \fBicmp-tstampreply\fP, \fBicmp-ireq\fP, \fBicmp-ireqreply\fP, \fBicmp-maskreq\fP, \fBicmp-maskreply\fP. The following TCP flags field values are available: \fBtcp-fin\fP, \fBtcp-syn\fP, \fBtcp-rst\fP, \fBtcp-push\fP, \fBtcp-ack\fP, \fBtcp-urg\fP. .LP Primitives may be combined using: .IP A parenthesized group of primitives and operators. .IP Negation (`\fB!\fP' or `\fBnot\fP'). .IP Concatenation (`\fB&&\fP' or `\fBand\fP'). .IP Alternation (`\fB||\fP' or `\fBor\fP'). .LP Negation has highest precedence. Alternation and concatenation have equal precedence and associate left to right. Note that explicit \fBand\fR tokens, not juxtaposition, are now required for concatenation. .LP If an identifier is given without a keyword, the most recent keyword is assumed. For example, .in +.5i .nf \fBnot host vs and ace\fR .fi .in -.5i is short for .in +.5i .nf \fBnot host vs and host ace\fR .fi .in -.5i which should not be confused with .in +.5i .nf \fBnot ( host vs or ace )\fR .fi .in -.5i .SH EXAMPLES .LP To select all packets arriving at or departing from \fIsundown\fP: .RS .nf \fBhost sundown\fP .fi .RE .LP To select traffic between \fIhelios\fR and either \fIhot\fR or \fIace\fR: .RS .nf \fBhost helios and \\( hot or ace \\)\fP .fi .RE .LP To select all IP packets between \fIace\fR and any host except \fIhelios\fR: .RS .nf \fBip host ace and not helios\fP .fi .RE .LP To select all traffic between local hosts and hosts at Berkeley: .RS .nf .B net ucb-ether .fi .RE .LP To select all ftp traffic through internet gateway \fIsnup\fP: .RS .nf .B gateway snup and (port ftp or ftp-data) .fi .RE .LP To select traffic neither sourced from nor destined for local hosts (if you gateway to one other net, this stuff should never make it onto your local net). .RS .nf .B ip and not net \fIlocalnet\fP .fi .RE .LP To select the start and end packets (the SYN and FIN packets) of each TCP conversation that involves a non-local host. .RS .nf .B tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net \fIlocalnet\fP .fi .RE .LP To select all IPv4 HTTP packets to and from port 80, i.e. print only packets that contain data, not, for example, SYN and FIN packets and ACK-only packets. (IPv6 is left as an exercise for the reader.) .RS .nf .B tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0) .fi .RE .LP To select IP packets longer than 576 bytes sent through gateway \fIsnup\fP: .RS .nf .B gateway snup and ip[2:2] > 576 .fi .RE .LP To select IP broadcast or multicast packets that were .I not sent via Ethernet broadcast or multicast: .RS .nf .B ether[0] & 1 = 0 and ip[16] >= 224 .fi .RE .LP To select all ICMP packets that are not echo requests/replies (i.e., not ping packets): .RS .nf .B icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply .fi .RE .SH "SEE ALSO" pcap(3PCAP) .SH BUGS Please send problems, bugs, questions, desirable enhancements, etc. to: .LP .RS tcpdump-workers@lists.tcpdump.org .RE .LP Filter expressions on fields other than those in Token Ring headers will not correctly handle source-routed Token Ring packets. .LP Filter expressions on fields other than those in 802.11 headers will not correctly handle 802.11 data packets with both To DS and From DS set. .LP .BR "ip6 proto" should chase header chain, but at this moment it does not. .BR "ip6 protochain" is supplied for this behavior. .LP Arithmetic expression against transport layer headers, like \fBtcp[0]\fP, does not work against IPv6 packets. It only looks at IPv4 packets. libpcap-1.8.1/pcap_datalink_name_to_val.3pcap0000644000026300017510000000347413003771737017364 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_DATALINK_NAME_TO_VAL 3PCAP "5 December 2014" .SH NAME pcap_datalink_name_to_val \- get the link-layer header type value corresponding to a header type name .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_datalink_name_to_val(const char *name); .ft .fi .SH DESCRIPTION .B pcap_datalink_name_to_val() translates a link-layer header type name, which is a .B DLT_ name with the .B DLT_ removed, to the corresponding link-layer header type value. The translation is case-insensitive. .SH RETURN VALUE .B pcap_datalink_name_to_val() returns the type value on success and \-1 if the name is not a known type name.. .SH SEE ALSO pcap(3PCAP) libpcap-1.8.1/pcap_activate.3pcap0000644000026300017510000000743413003771737015031 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_ACTIVATE 3PCAP "7 April 2014" .SH NAME pcap_activate \- activate a capture handle .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_activate(pcap_t *p); .ft .fi .SH DESCRIPTION .B pcap_activate() is used to activate a packet capture handle to look at packets on the network, with the options that were set on the handle being in effect. .SH RETURN VALUE .B pcap_activate() returns 0 on success without warnings, a non-zero positive value on success with warnings, and a negative value on error. A non-zero return value indicates what warning or error condition occurred. .LP The possible warning values are: .TP .B PCAP_WARNING_PROMISC_NOTSUP Promiscuous mode was requested, but the capture source doesn't support promiscuous mode. .TP .B PCAP_WARNING_TSTAMP_TYPE_NOTSUP The time stamp type specified in a previous .B pcap_set_tstamp_type() call isn't supported by the capture source (the time stamp type is left as the default), .TP .B PCAP_WARNING Another warning condition occurred; .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display a message describing the warning condition. .LP The possible error values are: .TP .B PCAP_ERROR_ACTIVATED The handle has already been activated. .TP .B PCAP_ERROR_NO_SUCH_DEVICE The capture source specified when the handle was created doesn't exist. .TP .B PCAP_ERROR_PERM_DENIED The process doesn't have permission to open the capture source. .TP .B PCAP_ERROR_PROMISC_PERM_DENIED The process has permission to open the capture source but doesn't have permission to put it into promiscuous mode. .TP .B PCAP_ERROR_RFMON_NOTSUP Monitor mode was specified but the capture source doesn't support monitor mode. .TP .B PCAP_ERROR_IFACE_NOT_UP The capture source device is not up. .TP .B PCAP_ERROR Another error occurred. .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display a message describing the error. .LP If .BR PCAP_WARNING_PROMISC_NOTSUP , .BR PCAP_ERROR_NO_SUCH_DEVICE , or .B PCAP_ERROR_PERM_DENIED is returned, .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display an message giving additional details about the problem that might be useful for debugging the problem if it's unexpected. .LP Additional warning and error codes may be added in the future; a program should check for positive, negative, and zero return codes, and treat all positive return codes as warnings and all negative return codes as errors. .B pcap_statustostr() can be called, with a warning or error code as an argument, to fetch a message describing the warning or error code. .SH SEE ALSO pcap(3PCAP) libpcap-1.8.1/pcap_set_tstamp_type.3pcap.in0000644000026300017510000000467313003771737017064 0ustar mcrmcr.\" .\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_SET_TSTAMP_TYPE 3PCAP "5 December 2014" .SH NAME pcap_set_tstamp_type \- set the time stamp type to be used by a capture device .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_set_tstamp_type(pcap_t *p, int tstamp_type); .ft .fi .SH DESCRIPTION .B pcap_set_tstamp_type() sets the the type of time stamp desired for packets captured on the pcap descriptor to the type specified by .IR tstamp_type . It must be called on a pcap descriptor created by .B pcap_create() that has not yet been activated by .BR pcap_activate() . .B pcap_list_tstamp_types() will give a list of the time stamp types supported by a given capture device. See .BR pcap-tstamp (@MAN_MISC_INFO@) for a list of all the time stamp types. .SH RETURN VALUE .B pcap_set_tstamp_type() returns 0 on success if the specified time stamp type is expected to be supported by the capture device, .B PCAP_WARNING_TSTAMP_TYPE_NOTSUP if the specified time stamp type is not supported by the capture device, .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated, and .B PCAP_ERROR_CANTSET_TSTAMP_TYPE if the capture device doesn't support setting the time stamp type. .SH SEE ALSO pcap(3PCAP), pcap_list_tstamp_types(3PCAP), pcap_tstamp_type_name_to_val(3PCAP), pcap-tstamp(@MAN_MISC_INFO@) libpcap-1.8.1/pcap-dbus.h0000644000026300017510000000015413003771737013315 0ustar mcrmcrpcap_t *dbus_create(const char *, char *, int *); int dbus_findalldevs(pcap_if_t **devlistp, char *errbuf); libpcap-1.8.1/pcap_fileno.3pcap0000644000026300017510000000413613003771737014501 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_FILENO 3PCAP "7 April 2014" .SH NAME pcap_fileno \- get the file descriptor for a live capture .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_fileno(pcap_t *p); .ft .fi .SH DESCRIPTION If .I p refers to a network device that was opened for a live capture using a combination of .B pcap_create() and .BR pcap_activate() , or using .BR pcap_open_live() , .B pcap_fileno() returns the file descriptor from which captured packets are read. .LP If .I p refers to a ``savefile'' that was opened using functions such as .BR pcap_open_offline() or .BR pcap_fopen_offline() , a ``dead'' .B pcap_t opened using .BR pcap_open_dead() , or a .B pcap_t that was created with .B pcap_create() but that has not yet been activated with .BR pcap_activate() , it returns \-1. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), pcap_open_live(3PCAP), pcap_open_offline(3PCAP), pcap_fopen_offline(3PCAP), pcap_open_dead(3PCAP) libpcap-1.8.1/pcap-snf.h0000644000026300017510000000015213003771737013144 0ustar mcrmcrpcap_t *snf_create(const char *, char *, int *); int snf_findalldevs(pcap_if_t **devlistp, char *errbuf); libpcap-1.8.1/pcap_set_rfmon.3pcap0000644000026300017510000000350413003771737015217 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_SET_RFMON 3PCAP "3 January 2014" .SH NAME pcap_set_rfmon \- set monitor mode for a not-yet-activated capture handle .SH SYNOPSIS .nf .ft B #include .LP .ft B int pcap_set_rfmon(pcap_t *p, int rfmon); .ft .fi .SH DESCRIPTION .B pcap_set_rfmon() sets whether monitor mode should be set on a capture handle when the handle is activated. If .I rfmon is non-zero, monitor mode will be set, otherwise it will not be set. .SH RETURN VALUE .B pcap_set_rfmon() returns 0 on success or .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), pcap_can_set_rfmon(3PCAP) libpcap-1.8.1/pcap_set_immediate_mode.3pcap0000644000026300017510000000356313003771737017045 0ustar mcrmcr.\" .\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_SET_IMMEDIATE_MODE 3PCAP "5 December 2013" .SH NAME pcap_set_immediate_mode \- set immediate mode for a not-yet-activated capture handle .SH SYNOPSIS .nf .ft B #include .LP .ft B int pcap_set_immediate_mode(pcap_t *p, int immediate_mode); .ft .fi .SH DESCRIPTION .B pcap_set_immediate_mode() sets whether immediate mode should be set on a capture handle when the handle is activated. If .I immediate_mode is non-zero, immediate mode will be set, otherwise it will not be set. .SH RETURN VALUE .B pcap_set_immediate_mode() returns 0 on success or .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) libpcap-1.8.1/pcap_open_dead.3pcap.in0000644000026300017510000000525313003771737015551 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_OPEN_DEAD 3PCAP "3 January 2014" .SH NAME pcap_open_dead, pcap_open_dead_with_tstamp_precision \- open a fake pcap_t for compiling filters or opening a capture for output .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B pcap_t *pcap_open_dead(int linktype, int snaplen); pcap_t *pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision); .ft .fi .SH DESCRIPTION .PP .B pcap_open_dead() and .B pcap_open_dead_with_tstamp_precision() are used for creating a .B pcap_t structure to use when calling the other functions in libpcap. It is typically used when just using libpcap for compiling BPF code; it can also be used if using .BR pcap_dump_open() , .BR pcap_dump() , and .B pcap_dump_close() to write a savefile if there is no .B pcap_t that supplies the packets to be written. .PP .I linktype specifies the link-layer type for the .BR pcap_t . .PP .I snaplen specifies the snapshot length for the .BR pcap_t . .PP When .BR pcap_open_dead_with_tstamp_precision() , is used to create a .B pcap_t for use with .BR pcap_dump_open() , .I precision specifies the time stamp precision for packets; .B PCAP_TSTAMP_PRECISION_MICRO should be specified if the packets to be written have time stamps in seconds and microseconds, and .B PCAP_TSTAMP_PRECISION_NANO should be specified if the packets to be written have time stamps in seconds and nanoseconds. Its value does not affect .BR pcap_compile() . .SH SEE ALSO pcap(3PCAP), pcap_compile(3PCAP), pcap_dump_open(3PCAP), pcap-linktype(@MAN_MISC_INFO@) libpcap-1.8.1/pcap-config.in0000644000026300017510000000313413003771737014005 0ustar mcrmcr#! /bin/sh # # Script to give the appropriate compiler flags and linker flags # to use when building code that uses libpcap. # prefix="@prefix@" exec_prefix="@exec_prefix@" includedir="@includedir@" libdir="@libdir@" V_RPATH_OPT="@V_RPATH_OPT@" LIBS="@LIBS@" static=0 show_cflags=0 show_libs=0 while [ "$#" != 0 ] do case "$1" in --static) static=1 ;; --cflags) show_cflags=1 ;; --libs) show_libs=1 ;; --additional-libs) show_additional_libs=1 ;; esac shift done if [ "$V_RPATH_OPT" != "" ] then # # If libdir isn't /usr/lib, add it to the run-time linker path. # if [ "$libdir" != "/usr/lib" ] then RPATH=$V_RPATH_OPT$libdir fi fi if [ "$static" = 1 ] then # # Include LIBS so that the flags include libraries containing # routines that libpcap uses. # if [ "$show_cflags" = 1 -a "$show_libs" = 1 ] then echo "-I$includedir -L$libdir -lpcap $LIBS" elif [ "$show_cflags" = 1 -a "$show_additional_libs" = 1 ] then echo "-I$includedir -L$libdir $LIBS" elif [ "$show_cflags" = 1 ] then echo "-I$includedir" elif [ "$show_libs" = 1 ] then echo "-L$libdir -lpcap $LIBS" elif [ "$show_additional_libs" = 1 ] then echo "$LIBS" fi else # # Omit LIBS - libpcap is assumed to be linked with those # libraries, so there's no need to do so explicitly. # if [ "$show_cflags" = 1 -a "$show_libs" = 1 ] then echo "-I$includedir -L$libdir $RPATH -lpcap" elif [ "$show_cflags" = 1 -a "$show_additional_libs" = 1 ] then echo "-I$includedir" elif [ "$show_cflags" = 1 ] then echo "-I$includedir" elif [ "$show_libs" = 1 ] then echo "-L$libdir $RPATH -lpcap" fi fi libpcap-1.8.1/pcap-libdlpi.c0000644000026300017510000002520013003771737013771 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. * * This code contributed by Sagun Shakya (sagun.shakya@sun.com) */ /* * Packet capture routines for DLPI using libdlpi under SunOS 5.11. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "pcap-int.h" #include "dlpisubs.h" /* Forwards. */ static int dlpromiscon(pcap_t *, bpf_u_int32); static int pcap_read_libdlpi(pcap_t *, int, pcap_handler, u_char *); static int pcap_inject_libdlpi(pcap_t *, const void *, size_t); static void pcap_libdlpi_err(const char *, const char *, int, char *); static void pcap_cleanup_libdlpi(pcap_t *); /* * list_interfaces() will list all the network links that are * available on a system. */ static boolean_t list_interfaces(const char *, void *); typedef struct linknamelist { char linkname[DLPI_LINKNAME_MAX]; struct linknamelist *lnl_next; } linknamelist_t; typedef struct linkwalk { linknamelist_t *lw_list; int lw_err; } linkwalk_t; /* * The caller of this function should free the memory allocated * for each linknamelist_t "entry" allocated. */ static boolean_t list_interfaces(const char *linkname, void *arg) { linkwalk_t *lwp = arg; linknamelist_t *entry; if ((entry = calloc(1, sizeof(linknamelist_t))) == NULL) { lwp->lw_err = ENOMEM; return (B_TRUE); } (void) strlcpy(entry->linkname, linkname, DLPI_LINKNAME_MAX); if (lwp->lw_list == NULL) { lwp->lw_list = entry; } else { entry->lnl_next = lwp->lw_list; lwp->lw_list = entry; } return (B_FALSE); } static int pcap_activate_libdlpi(pcap_t *p) { struct pcap_dlpi *pd = p->priv; int status = 0; int retv; dlpi_handle_t dh; dlpi_info_t dlinfo; /* * Enable Solaris raw and passive DLPI extensions; * dlpi_open() will not fail if the underlying link does not support * passive mode. See dlpi(7P) for details. */ retv = dlpi_open(p->opt.device, &dh, DLPI_RAW|DLPI_PASSIVE); if (retv != DLPI_SUCCESS) { if (retv == DLPI_ELINKNAMEINVAL || retv == DLPI_ENOLINK) status = PCAP_ERROR_NO_SUCH_DEVICE; else if (retv == DL_SYSERR && (errno == EPERM || errno == EACCES)) status = PCAP_ERROR_PERM_DENIED; else status = PCAP_ERROR; pcap_libdlpi_err(p->opt.device, "dlpi_open", retv, p->errbuf); return (status); } pd->dlpi_hd = dh; if (p->opt.rfmon) { /* * This device exists, but we don't support monitor mode * any platforms that support DLPI. */ status = PCAP_ERROR_RFMON_NOTSUP; goto bad; } /* Bind with DLPI_ANY_SAP. */ if ((retv = dlpi_bind(pd->dlpi_hd, DLPI_ANY_SAP, 0)) != DLPI_SUCCESS) { status = PCAP_ERROR; pcap_libdlpi_err(p->opt.device, "dlpi_bind", retv, p->errbuf); goto bad; } /* Enable promiscuous mode. */ if (p->opt.promisc) { retv = dlpromiscon(p, DL_PROMISC_PHYS); if (retv < 0) { /* * "You don't have permission to capture on * this device" and "you don't have permission * to capture in promiscuous mode on this * device" are different; let the user know, * so if they can't get permission to * capture in promiscuous mode, they can at * least try to capture in non-promiscuous * mode. * * XXX - you might have to capture in * promiscuous mode to see outgoing packets. */ if (retv == PCAP_ERROR_PERM_DENIED) status = PCAP_ERROR_PROMISC_PERM_DENIED; else status = retv; goto bad; } } else { /* Try to enable multicast. */ retv = dlpromiscon(p, DL_PROMISC_MULTI); if (retv < 0) { status = retv; goto bad; } } /* Try to enable SAP promiscuity. */ retv = dlpromiscon(p, DL_PROMISC_SAP); if (retv < 0) { /* * Not fatal, since the DL_PROMISC_PHYS mode worked. * Report it as a warning, however. */ if (p->opt.promisc) status = PCAP_WARNING; else { status = retv; goto bad; } } /* Determine link type. */ if ((retv = dlpi_info(pd->dlpi_hd, &dlinfo, 0)) != DLPI_SUCCESS) { status = PCAP_ERROR; pcap_libdlpi_err(p->opt.device, "dlpi_info", retv, p->errbuf); goto bad; } if (pcap_process_mactype(p, dlinfo.di_mactype) != 0) { status = PCAP_ERROR; goto bad; } p->fd = dlpi_fd(pd->dlpi_hd); /* Push and configure bufmod. */ if (pcap_conf_bufmod(p, p->snapshot) != 0) { status = PCAP_ERROR; goto bad; } /* * Flush the read side. */ if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { status = PCAP_ERROR; pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s", pcap_strerror(errno)); goto bad; } /* Allocate data buffer. */ if (pcap_alloc_databuf(p) != 0) { status = PCAP_ERROR; goto bad; } /* * "p->fd" is a FD for a STREAMS device, so "select()" and * "poll()" should work on it. */ p->selectable_fd = p->fd; p->read_op = pcap_read_libdlpi; p->inject_op = pcap_inject_libdlpi; p->setfilter_op = install_bpf_program; /* No kernel filtering */ p->setdirection_op = NULL; /* Not implemented */ p->set_datalink_op = NULL; /* Can't change data link type */ p->getnonblock_op = pcap_getnonblock_fd; p->setnonblock_op = pcap_setnonblock_fd; p->stats_op = pcap_stats_dlpi; p->cleanup_op = pcap_cleanup_libdlpi; return (status); bad: pcap_cleanup_libdlpi(p); return (status); } #define STRINGIFY(n) #n static int dlpromiscon(pcap_t *p, bpf_u_int32 level) { struct pcap_dlpi *pd = p->priv; int retv; int err; retv = dlpi_promiscon(pd->dlpi_hd, level); if (retv != DLPI_SUCCESS) { if (retv == DL_SYSERR && (errno == EPERM || errno == EACCES)) err = PCAP_ERROR_PERM_DENIED; else err = PCAP_ERROR; pcap_libdlpi_err(p->opt.device, "dlpi_promiscon" STRINGIFY(level), retv, p->errbuf); return (err); } return (0); } /* * Presumably everything returned by dlpi_walk() is a DLPI device, * so there's no work to be done here to check whether name refers * to a DLPI device. */ static int is_dlpi_interface(const char *name _U_) { return (1); } /* * In Solaris, the "standard" mechanism" i.e SIOCGLIFCONF will only find * network links that are plumbed and are up. dlpi_walk(3DLPI) will find * additional network links present in the system. */ int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { int retv = 0; linknamelist_t *entry, *next; linkwalk_t lw = {NULL, 0}; int save_errno; /* * Get the list of regular interfaces first. */ if (pcap_findalldevs_interfaces(alldevsp, errbuf, is_dlpi_interface) == -1) return (-1); /* failure */ /* dlpi_walk() for loopback will be added here. */ dlpi_walk(list_interfaces, &lw, 0); if (lw.lw_err != 0) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "dlpi_walk: %s", pcap_strerror(lw.lw_err)); retv = -1; goto done; } /* Add linkname if it does not exist on the list. */ for (entry = lw.lw_list; entry != NULL; entry = entry->lnl_next) { if (pcap_add_if(alldevsp, entry->linkname, 0, NULL, errbuf) < 0) retv = -1; } done: save_errno = errno; for (entry = lw.lw_list; entry != NULL; entry = next) { next = entry->lnl_next; free(entry); } errno = save_errno; return (retv); } /* * Read data received on DLPI handle. Returns -2 if told to terminate, else * returns the number of packets read. */ static int pcap_read_libdlpi(pcap_t *p, int count, pcap_handler callback, u_char *user) { struct pcap_dlpi *pd = p->priv; int len; u_char *bufp; size_t msglen; int retv; len = p->cc; if (len != 0) { bufp = p->bp; goto process_pkts; } do { /* Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that it has, * and return -2 to indicate that we were told to * break out of the loop. */ p->break_loop = 0; return (-2); } msglen = p->bufsize; bufp = (u_char *)p->buffer + p->offset; retv = dlpi_recv(pd->dlpi_hd, NULL, NULL, bufp, &msglen, -1, NULL); if (retv != DLPI_SUCCESS) { /* * This is most likely a call to terminate out of the * loop. So, do not return an error message, instead * check if "pcap_breakloop()" has been called above. */ if (retv == DL_SYSERR && errno == EINTR) { len = 0; continue; } pcap_libdlpi_err(dlpi_linkname(pd->dlpi_hd), "dlpi_recv", retv, p->errbuf); return (-1); } len = msglen; } while (len == 0); process_pkts: return (pcap_process_pkts(p, callback, user, count, bufp, len)); } static int pcap_inject_libdlpi(pcap_t *p, const void *buf, size_t size) { struct pcap_dlpi *pd = p->priv; int retv; retv = dlpi_send(pd->dlpi_hd, NULL, 0, buf, size, NULL); if (retv != DLPI_SUCCESS) { pcap_libdlpi_err(dlpi_linkname(pd->dlpi_hd), "dlpi_send", retv, p->errbuf); return (-1); } /* * dlpi_send(3DLPI) does not provide a way to return the number of * bytes sent on the wire. Based on the fact that DLPI_SUCCESS was * returned we are assuming 'size' bytes were sent. */ return (size); } /* * Close dlpi handle. */ static void pcap_cleanup_libdlpi(pcap_t *p) { struct pcap_dlpi *pd = p->priv; if (pd->dlpi_hd != NULL) { dlpi_close(pd->dlpi_hd); pd->dlpi_hd = NULL; p->fd = -1; } pcap_cleanup_live_common(p); } /* * Write error message to buffer. */ static void pcap_libdlpi_err(const char *linkname, const char *func, int err, char *errbuf) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "libpcap: %s failed on %s: %s", func, linkname, dlpi_strerror(err)); } pcap_t * pcap_create_interface(const char *device _U_, char *ebuf) { pcap_t *p; p = pcap_create_common(ebuf, sizeof (struct pcap_dlpi)); if (p == NULL) return (NULL); p->activate_op = pcap_activate_libdlpi; return (p); } libpcap-1.8.1/pcap-win32.c0000644000026300017510000011314513003771737013322 0ustar mcrmcr/* * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino, CACE Technologies * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #define PCAP_DONT_INCLUDE_PCAP_BPF_H #include #include #include #ifdef __MINGW32__ #ifdef __MINGW64__ #include #else /*__MINGW64__*/ #include #include #endif /*__MINGW64__*/ #else /*__MINGW32__*/ #include #endif /*__MINGW32__*/ #ifdef HAVE_DAG_API #include #include #endif /* HAVE_DAG_API */ #ifdef __MINGW32__ int* _errno(); #define errno (*_errno()) #endif /* __MINGW32__ */ #ifdef HAVE_REMOTE #include "pcap-rpcap.h" #endif /* HAVE_REMOTE */ static int pcap_setfilter_win32_npf(pcap_t *, struct bpf_program *); static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *); static int pcap_getnonblock_win32(pcap_t *, char *); static int pcap_setnonblock_win32(pcap_t *, int, char *); /*dimension of the buffer in the pcap_t structure*/ #define WIN32_DEFAULT_USER_BUFFER_SIZE 256000 /*dimension of the buffer in the kernel driver NPF */ #define WIN32_DEFAULT_KERNEL_BUFFER_SIZE 1000000 /* Equivalent to ntohs(), but a lot faster under Windows */ #define SWAPS(_X) ((_X & 0xff) << 8) | (_X >> 8) /* * Private data for capturing on WinPcap devices. */ struct pcap_win { int nonblock; int rfmon_selfstart; /* a flag tells whether the monitor mode is set by itself */ int filtering_in_kernel; /* using kernel filter */ #ifdef HAVE_DAG_API int dag_fcs_bits; /* Number of checksum bits from link layer */ #endif }; BOOL WINAPI DllMain( HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved ) { return (TRUE); } /* * Define stub versions of the monitor-mode support routines if this * isn't Npcap. HAVE_NPCAP_PACKET_API is defined by Npcap but not * WinPcap. */ #ifndef HAVE_NPCAP_PACKET_API static int PacketIsMonitorModeSupported(PCHAR AdapterName _U_) { /* * We don't support monitor mode. */ return (0); } static int PacketSetMonitorMode(PCHAR AdapterName _U_, int mode _U_) { /* * This should never be called, as PacketIsMonitorModeSupported() * will return 0, meaning "we don't support monitor mode, so * don't try to turn it on or off". */ return (0); } static int PacketGetMonitorMode(PCHAR AdapterName _U_) { /* * This should fail, so that pcap_activate_win32() returns * PCAP_ERROR_RFMON_NOTSUP if our caller requested monitor * mode. */ return (-1); } #endif /* Start winsock */ int wsockinit(void) { WORD wVersionRequested; WSADATA wsaData; static int err = -1; static int done = 0; if (done) return (err); wVersionRequested = MAKEWORD( 1, 1); err = WSAStartup( wVersionRequested, &wsaData ); atexit ((void(*)(void))WSACleanup); done = 1; if ( err != 0 ) err = -1; return (err); } int pcap_wsockinit(void) { return (wsockinit()); } static int pcap_stats_win32(pcap_t *p, struct pcap_stat *ps) { struct bpf_stat bstats; char errbuf[PCAP_ERRBUF_SIZE+1]; /* * Try to get statistics. * * (Please note - "struct pcap_stat" is *not* the same as * WinPcap's "struct bpf_stat". It might currently have the * same layout, but let's not cheat. * * Note also that we don't fill in ps_capt, as we might have * been called by code compiled against an earlier version of * WinPcap that didn't have ps_capt, in which case filling it * in would stomp on whatever comes after the structure passed * to us. */ if (!PacketGetStats(p->adapter, &bstats)) { pcap_win32_err_to_str(GetLastError(), errbuf); pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "PacketGetStats error: %s", errbuf); return (-1); } ps->ps_recv = bstats.bs_recv; ps->ps_drop = bstats.bs_drop; /* * XXX - PacketGetStats() doesn't fill this in, so we just * return 0. */ #if 0 ps->ps_ifdrop = bstats.ps_ifdrop; #else ps->ps_ifdrop = 0; #endif return (0); } /* * Win32-only routine for getting statistics. * * This way is definitely safer than passing the pcap_stat * from the userland. * In fact, there could happen than the user allocates a variable which is not * big enough for the new structure, and the library will write in a zone * which is not allocated to this variable. * * In this way, we're pretty sure we are writing on memory allocated to this * variable. * * XXX - but this is the wrong way to handle statistics. Instead, we should * have an API that returns data in a form like the Options section of a * pcapng Interface Statistics Block: * * http://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6 * * which would let us add new statistics straightforwardly and indicate which * statistics we are and are *not* providing, rather than having to provide * possibly-bogus values for statistics we can't provide. */ struct pcap_stat * pcap_stats_ex_win32(pcap_t *p, int *pcap_stat_size) { struct bpf_stat bstats; char errbuf[PCAP_ERRBUF_SIZE+1]; *pcap_stat_size = sizeof (p->stat); /* * Try to get statistics. * * (Please note - "struct pcap_stat" is *not* the same as * WinPcap's "struct bpf_stat". It might currently have the * same layout, but let's not cheat.) */ if (!PacketGetStatsEx(p->adapter, &bstats)) { pcap_win32_err_to_str(GetLastError(), errbuf); pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "PacketGetStatsEx error: %s", errbuf); return (NULL); } p->stat.ps_recv = bstats.bs_recv; p->stat.ps_drop = bstats.bs_drop; p->stat.ps_ifdrop = bstats.ps_ifdrop; #ifdef HAVE_REMOTE p->stat.ps_capt = bstats.bs_capt; #endif return (&p->stat); } /* Set the dimension of the kernel-level capture buffer */ static int pcap_setbuff_win32(pcap_t *p, int dim) { if(PacketSetBuff(p->adapter,dim)==FALSE) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); return (-1); } return (0); } /* Set the driver working mode */ static int pcap_setmode_win32(pcap_t *p, int mode) { if(PacketSetMode(p->adapter,mode)==FALSE) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized"); return (-1); } return (0); } /*set the minimum amount of data that will release a read call*/ static int pcap_setmintocopy_win32(pcap_t *p, int size) { if(PacketSetMinToCopy(p->adapter, size)==FALSE) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size"); return (-1); } return (0); } static HANDLE pcap_getevent_win32(pcap_t *p) { return (PacketGetReadEvent(p->adapter)); } static int pcap_oid_get_request_win32(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp) { PACKET_OID_DATA *oid_data_arg; char errbuf[PCAP_ERRBUF_SIZE+1]; /* * Allocate a PACKET_OID_DATA structure to hand to PacketRequest(). * It should be big enough to hold "*lenp" bytes of data; it * will actually be slightly larger, as PACKET_OID_DATA has a * 1-byte data array at the end, standing in for the variable-length * data that's actually there. */ oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp); if (oid_data_arg == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Couldn't allocate argument buffer for PacketRequest"); return (PCAP_ERROR); } /* * No need to copy the data - we're doing a fetch. */ oid_data_arg->Oid = oid; oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */ if (!PacketRequest(p->adapter, FALSE, oid_data_arg)) { pcap_win32_err_to_str(GetLastError(), errbuf); pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error calling PacketRequest: %s", errbuf); free(oid_data_arg); return (PCAP_ERROR); } /* * Get the length actually supplied. */ *lenp = oid_data_arg->Length; /* * Copy back the data we fetched. */ memcpy(data, oid_data_arg->Data, *lenp); free(oid_data_arg); return (0); } static int pcap_oid_set_request_win32(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp) { PACKET_OID_DATA *oid_data_arg; char errbuf[PCAP_ERRBUF_SIZE+1]; /* * Allocate a PACKET_OID_DATA structure to hand to PacketRequest(). * It should be big enough to hold "*lenp" bytes of data; it * will actually be slightly larger, as PACKET_OID_DATA has a * 1-byte data array at the end, standing in for the variable-length * data that's actually there. */ oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp); if (oid_data_arg == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Couldn't allocate argument buffer for PacketRequest"); return (PCAP_ERROR); } oid_data_arg->Oid = oid; oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */ memcpy(oid_data_arg->Data, data, *lenp); if (!PacketRequest(p->adapter, TRUE, oid_data_arg)) { pcap_win32_err_to_str(GetLastError(), errbuf); pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error calling PacketRequest: %s", errbuf); free(oid_data_arg); return (PCAP_ERROR); } /* * Get the length actually copied. */ *lenp = oid_data_arg->Length; /* * No need to copy the data - we're doing a set. */ free(oid_data_arg); return (0); } static u_int pcap_sendqueue_transmit_win32(pcap_t *p, pcap_send_queue *queue, int sync) { u_int res; char errbuf[PCAP_ERRBUF_SIZE+1]; if (p->adapter==NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Cannot transmit a queue to an offline capture or to a TurboCap port"); return (0); } res = PacketSendPackets(p->adapter, queue->buffer, queue->len, (BOOLEAN)sync); if(res != queue->len){ pcap_win32_err_to_str(GetLastError(), errbuf); pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", errbuf); } return (res); } static int pcap_setuserbuffer_win32(pcap_t *p, int size) { unsigned char *new_buff; if (size<=0) { /* Bogus parameter */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error: invalid size %d",size); return (-1); } /* Allocate the buffer */ new_buff=(unsigned char*)malloc(sizeof(char)*size); if (!new_buff) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error: not enough memory"); return (-1); } free(p->buffer); p->buffer=new_buff; p->bufsize=size; return (0); } static int pcap_live_dump_win32(pcap_t *p, char *filename, int maxsize, int maxpacks) { BOOLEAN res; /* Set the packet driver in dump mode */ res = PacketSetMode(p->adapter, PACKET_MODE_DUMP); if(res == FALSE){ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error setting dump mode"); return (-1); } /* Set the name of the dump file */ res = PacketSetDumpName(p->adapter, filename, (int)strlen(filename)); if(res == FALSE){ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error setting kernel dump file name"); return (-1); } /* Set the limits of the dump file */ res = PacketSetDumpLimits(p->adapter, maxsize, maxpacks); return (0); } static int pcap_live_dump_ended_win32(pcap_t *p, int sync) { return (PacketIsDumpEnded(p->adapter, (BOOLEAN)sync)); } static PAirpcapHandle pcap_get_airpcap_handle_win32(pcap_t *p) { #ifdef HAVE_AIRPCAP_API return (PacketGetAirPcapHandle(p->adapter)); #else return (NULL); #endif /* HAVE_AIRPCAP_API */ } static int pcap_read_win32_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { PACKET Packet; int cc; int n = 0; register u_char *bp, *ep; u_char *datap; struct pcap_win *pw = p->priv; cc = p->cc; if (p->cc == 0) { /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that it * has, and return PCAP_ERROR_BREAK to indicate * that we were told to break out of the loop. */ p->break_loop = 0; return (PCAP_ERROR_BREAK); } /* * Capture the packets. * * The PACKET structure had a bunch of extra stuff for * Windows 9x/Me, but the only interesting data in it * in the versions of Windows that we support is just * a copy of p->buffer, a copy of p->buflen, and the * actual number of bytes read returned from * PacketReceivePacket(), none of which has to be * retained from call to call, so we just keep one on * the stack. */ PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize); if (!PacketReceivePacket(p->adapter, &Packet, TRUE)) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); return (PCAP_ERROR); } cc = Packet.ulBytesReceived; bp = p->buffer; } else bp = p->bp; /* * Loop through each packet. */ #define bhp ((struct bpf_hdr *)bp) ep = bp + cc; while (1) { register int caplen, hdrlen; /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return PCAP_ERROR_BREAK * to indicate that we were told to break out of the loop, * otherwise leave the flag set, so that the *next* call * will break out of the loop without having read any * packets, and return the number of packets we've * processed so far. */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return (PCAP_ERROR_BREAK); } else { p->bp = bp; p->cc = (int) (ep - bp); return (n); } } if (bp >= ep) break; caplen = bhp->bh_caplen; hdrlen = bhp->bh_hdrlen; datap = bp + hdrlen; /* * Short-circuit evaluation: if using BPF filter * in kernel, no need to do it now - we already know * the packet passed the filter. * * XXX - bpf_filter() should always return TRUE if * handed a null pointer for the program, but it might * just try to "run" the filter, so we check here. */ if (pw->filtering_in_kernel || p->fcode.bf_insns == NULL || bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) { /* * XXX A bpf_hdr matches a pcap_pkthdr. */ (*callback)(user, (struct pcap_pkthdr*)bp, datap); bp += Packet_WORDALIGN(caplen + hdrlen); if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { p->bp = bp; p->cc = (int) (ep - bp); return (n); } } else { /* * Skip this packet. */ bp += Packet_WORDALIGN(caplen + hdrlen); } } #undef bhp p->cc = 0; return (n); } #ifdef HAVE_DAG_API static int pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct pcap_win *pw = p->priv; PACKET Packet; u_char *dp = NULL; int packet_len = 0, caplen = 0; struct pcap_pkthdr pcap_header; u_char *endofbuf; int n = 0; dag_record_t *header; unsigned erf_record_len; ULONGLONG ts; int cc; unsigned swt; unsigned dfp = p->adapter->DagFastProcess; cc = p->cc; if (cc == 0) /* Get new packets only if we have processed all the ones of the previous read */ { /* * Get new packets from the network. * * The PACKET structure had a bunch of extra stuff for * Windows 9x/Me, but the only interesting data in it * in the versions of Windows that we support is just * a copy of p->buffer, a copy of p->buflen, and the * actual number of bytes read returned from * PacketReceivePacket(), none of which has to be * retained from call to call, so we just keep one on * the stack. */ PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize); if (!PacketReceivePacket(p->adapter, &Packet, TRUE)) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); return (-1); } cc = Packet.ulBytesReceived; if(cc == 0) /* The timeout has expired but we no packets arrived */ return (0); header = (dag_record_t*)p->adapter->DagBuffer; } else header = (dag_record_t*)p->bp; endofbuf = (char*)header + cc; /* * Cycle through the packets */ do { erf_record_len = SWAPS(header->rlen); if((char*)header + erf_record_len > endofbuf) break; /* Increase the number of captured packets */ p->stat.ps_recv++; /* Find the beginning of the packet */ dp = ((u_char *)header) + dag_record_size; /* Determine actual packet len */ switch(header->type) { case TYPE_ATM: packet_len = ATM_SNAPLEN; caplen = ATM_SNAPLEN; dp += 4; break; case TYPE_ETH: swt = SWAPS(header->wlen); packet_len = swt - (pw->dag_fcs_bits); caplen = erf_record_len - dag_record_size - 2; if (caplen > packet_len) { caplen = packet_len; } dp += 2; break; case TYPE_HDLC_POS: swt = SWAPS(header->wlen); packet_len = swt - (pw->dag_fcs_bits); caplen = erf_record_len - dag_record_size; if (caplen > packet_len) { caplen = packet_len; } break; } if(caplen > p->snapshot) caplen = p->snapshot; /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return -2 to indicate * that we were told to break out of the loop, otherwise * leave the flag set, so that the *next* call will break * out of the loop without having read any packets, and * return the number of packets we've processed so far. */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return (-2); } else { p->bp = (char*)header; p->cc = endofbuf - (char*)header; return (n); } } if(!dfp) { /* convert between timestamp formats */ ts = header->ts; pcap_header.ts.tv_sec = (int)(ts >> 32); ts = (ts & 0xffffffffi64) * 1000000; ts += 0x80000000; /* rounding */ pcap_header.ts.tv_usec = (int)(ts >> 32); if (pcap_header.ts.tv_usec >= 1000000) { pcap_header.ts.tv_usec -= 1000000; pcap_header.ts.tv_sec++; } } /* No underlaying filtering system. We need to filter on our own */ if (p->fcode.bf_insns) { if (bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0) { /* Move to next packet */ header = (dag_record_t*)((char*)header + erf_record_len); continue; } } /* Fill the header for the user suppplied callback function */ pcap_header.caplen = caplen; pcap_header.len = packet_len; /* Call the callback function */ (*callback)(user, &pcap_header, dp); /* Move to next packet */ header = (dag_record_t*)((char*)header + erf_record_len); /* Stop if the number of packets requested by user has been reached*/ if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { p->bp = (char*)header; p->cc = endofbuf - (char*)header; return (n); } } while((u_char*)header < endofbuf); return (1); } #endif /* HAVE_DAG_API */ /* Send a packet to the network */ static int pcap_inject_win32(pcap_t *p, const void *buf, size_t size){ LPPACKET PacketToSend; PacketToSend=PacketAllocatePacket(); if (PacketToSend == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketAllocatePacket failed"); return (-1); } PacketInitPacket(PacketToSend, (PVOID)buf, (UINT)size); if(PacketSendPacket(p->adapter,PacketToSend,TRUE) == FALSE){ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed"); PacketFreePacket(PacketToSend); return (-1); } PacketFreePacket(PacketToSend); /* * We assume it all got sent if "PacketSendPacket()" succeeded. * "pcap_inject()" is expected to return the number of bytes * sent. */ return ((int)size); } static void pcap_cleanup_win32(pcap_t *p) { struct pcap_win *pw = p->priv; if (p->adapter != NULL) { PacketCloseAdapter(p->adapter); p->adapter = NULL; } if (pw->rfmon_selfstart) { PacketSetMonitorMode(p->opt.device, 0); } pcap_cleanup_live_common(p); } static int pcap_activate_win32(pcap_t *p) { struct pcap_win *pw = p->priv; NetType type; int res; char errbuf[PCAP_ERRBUF_SIZE+1]; #ifdef HAVE_REMOTE char host[PCAP_BUF_SIZE + 1]; char port[PCAP_BUF_SIZE + 1]; char name[PCAP_BUF_SIZE + 1]; int srctype; int opensource_remote_result; struct pcap_md *md; /* structure used when doing a remote live capture */ md = (struct pcap_md *) ((u_char*)p->priv + sizeof(struct pcap_win)); /* Retrofit; we have to make older applications compatible with the remote capture So, we're calling the pcap_open_remote() from here, that is a very dirty thing. Obviously, we cannot exploit all the new features; for instance, we cannot send authentication, we cannot use a UDP data connection, and so on. */ if (pcap_parsesrcstr(p->opt.device, &srctype, host, port, name, p->errbuf)) return PCAP_ERROR; if (srctype == PCAP_SRC_IFREMOTE) { opensource_remote_result = pcap_opensource_remote(p, NULL); if (opensource_remote_result != 0) return opensource_remote_result; md->rmt_flags = (p->opt.promisc) ? PCAP_OPENFLAG_PROMISCUOUS : 0; return 0; } if (srctype == PCAP_SRC_IFLOCAL) { /* * If it starts with rpcap://, cut down the string */ if (strncmp(p->opt.device, PCAP_SRC_IF_STRING, strlen(PCAP_SRC_IF_STRING)) == 0) { size_t len = strlen(p->opt.device) - strlen(PCAP_SRC_IF_STRING) + 1; char *new_string; /* * allocate a new string and free the old one */ if (len > 0) { new_string = (char*)malloc(len); if (new_string != NULL) { char *tmp; strcpy_s(new_string, len, p->opt.device + strlen(PCAP_SRC_IF_STRING)); tmp = p->opt.device; p->opt.device = new_string; free(tmp); } } } } #endif /* HAVE_REMOTE */ if (p->opt.rfmon) { /* * Monitor mode is supported on Windows Vista and later. */ if (PacketGetMonitorMode(p->opt.device) == 1) { pw->rfmon_selfstart = 0; } else { if ((res = PacketSetMonitorMode(p->opt.device, 1)) != 1) { pw->rfmon_selfstart = 0; // Monitor mode is not supported. if (res == 0) { return PCAP_ERROR_RFMON_NOTSUP; } else { return PCAP_ERROR; } } else { pw->rfmon_selfstart = 1; } } } /* Init WinSock */ wsockinit(); p->adapter = PacketOpenAdapter(p->opt.device); if (p->adapter == NULL) { /* Adapter detected but we are not able to open it. Return failure. */ pcap_win32_err_to_str(GetLastError(), errbuf); if (pw->rfmon_selfstart) { PacketSetMonitorMode(p->opt.device, 0); } pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", errbuf); return (PCAP_ERROR); } /*get network type*/ if(PacketGetNetType (p->adapter,&type) == FALSE) { pcap_win32_err_to_str(GetLastError(), errbuf); pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", errbuf); goto bad; } /*Set the linktype*/ switch (type.LinkType) { case NdisMediumWan: p->linktype = DLT_EN10MB; break; case NdisMedium802_3: p->linktype = DLT_EN10MB; /* * This is (presumably) a real Ethernet capture; give it a * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so * that an application can let you choose it, in case you're * capturing DOCSIS traffic that a Cisco Cable Modem * Termination System is putting out onto an Ethernet (it * doesn't put an Ethernet header onto the wire, it puts raw * DOCSIS frames out on the wire inside the low-level * Ethernet framing). */ p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (p->dlt_list != NULL) { p->dlt_list[0] = DLT_EN10MB; p->dlt_list[1] = DLT_DOCSIS; p->dlt_count = 2; } break; case NdisMediumFddi: p->linktype = DLT_FDDI; break; case NdisMedium802_5: p->linktype = DLT_IEEE802; break; case NdisMediumArcnetRaw: p->linktype = DLT_ARCNET; break; case NdisMediumArcnet878_2: p->linktype = DLT_ARCNET; break; case NdisMediumAtm: p->linktype = DLT_ATM_RFC1483; break; case NdisMediumCHDLC: p->linktype = DLT_CHDLC; break; case NdisMediumPPPSerial: p->linktype = DLT_PPP_SERIAL; break; case NdisMediumNull: p->linktype = DLT_NULL; break; case NdisMediumBare80211: p->linktype = DLT_IEEE802_11; break; case NdisMediumRadio80211: p->linktype = DLT_IEEE802_11_RADIO; break; case NdisMediumPpi: p->linktype = DLT_PPI; break; default: p->linktype = DLT_EN10MB; /*an unknown adapter is assumed to be ethernet*/ break; } /* Set promiscuous mode */ if (p->opt.promisc) { if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode"); goto bad; } } else { if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL) == FALSE) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode"); goto bad; } } /* Set the buffer size */ p->bufsize = WIN32_DEFAULT_USER_BUFFER_SIZE; if(!(p->adapter->Flags & INFO_FLAG_DAG_CARD)) { /* * Traditional Adapter */ /* * If the buffer size wasn't explicitly set, default to * WIN32_DEFAULT_KERNEL_BUFFER_SIZE. */ if (p->opt.buffer_size == 0) p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE; if(PacketSetBuff(p->adapter,p->opt.buffer_size)==FALSE) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); goto bad; } p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); goto bad; } if (p->opt.immediate) { /* tell the driver to copy the buffer as soon as data arrives */ if(PacketSetMinToCopy(p->adapter,0)==FALSE) { pcap_win32_err_to_str(GetLastError(), errbuf); pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error calling PacketSetMinToCopy: %s", errbuf); goto bad; } } else { /* tell the driver to copy the buffer only if it contains at least 16K */ if(PacketSetMinToCopy(p->adapter,16000)==FALSE) { pcap_win32_err_to_str(GetLastError(), errbuf); pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error calling PacketSetMinToCopy: %s", errbuf); goto bad; } } } else #ifdef HAVE_DAG_API { /* * Dag Card */ LONG status; HKEY dagkey; DWORD lptype; DWORD lpcbdata; int postype = 0; char keyname[512]; pcap_snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s", "SYSTEM\\CurrentControlSet\\Services\\DAG", strstr(_strlwr(p->opt.device), "dag")); do { status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &dagkey); if(status != ERROR_SUCCESS) break; status = RegQueryValueEx(dagkey, "PosType", NULL, &lptype, (char*)&postype, &lpcbdata); if(status != ERROR_SUCCESS) { postype = 0; } RegCloseKey(dagkey); } while(FALSE); p->snapshot = PacketSetSnapLen(p->adapter, snaplen); /* Set the length of the FCS associated to any packet. This value * will be subtracted to the packet length */ pw->dag_fcs_bits = p->adapter->DagFcsLen; } #else goto bad; #endif /* HAVE_DAG_API */ PacketSetReadTimeout(p->adapter, p->opt.timeout); #ifdef HAVE_DAG_API if(p->adapter->Flags & INFO_FLAG_DAG_CARD) { /* install dag specific handlers for read and setfilter */ p->read_op = pcap_read_win32_dag; p->setfilter_op = pcap_setfilter_win32_dag; } else { #endif /* HAVE_DAG_API */ /* install traditional npf handlers for read and setfilter */ p->read_op = pcap_read_win32_npf; p->setfilter_op = pcap_setfilter_win32_npf; #ifdef HAVE_DAG_API } #endif /* HAVE_DAG_API */ p->setdirection_op = NULL; /* Not implemented. */ /* XXX - can this be implemented on some versions of Windows? */ p->inject_op = pcap_inject_win32; p->set_datalink_op = NULL; /* can't change data link type */ p->getnonblock_op = pcap_getnonblock_win32; p->setnonblock_op = pcap_setnonblock_win32; p->stats_op = pcap_stats_win32; p->stats_ex_op = pcap_stats_ex_win32; p->setbuff_op = pcap_setbuff_win32; p->setmode_op = pcap_setmode_win32; p->setmintocopy_op = pcap_setmintocopy_win32; p->getevent_op = pcap_getevent_win32; p->oid_get_request_op = pcap_oid_get_request_win32; p->oid_set_request_op = pcap_oid_set_request_win32; p->sendqueue_transmit_op = pcap_sendqueue_transmit_win32; p->setuserbuffer_op = pcap_setuserbuffer_win32; p->live_dump_op = pcap_live_dump_win32; p->live_dump_ended_op = pcap_live_dump_ended_win32; p->get_airpcap_handle_op = pcap_get_airpcap_handle_win32; p->cleanup_op = pcap_cleanup_win32; return (0); bad: pcap_cleanup_win32(p); return (PCAP_ERROR); } /* * Check if rfmon mode is supported on the pcap_t for Windows systems. */ static int pcap_can_set_rfmon_win32(pcap_t *p) { return (PacketIsMonitorModeSupported(p->opt.device) == 1); } pcap_t * pcap_create_interface(const char *device _U_, char *ebuf) { pcap_t *p; #ifdef HAVE_REMOTE p = pcap_create_common(ebuf, sizeof(struct pcap_win) + sizeof(struct pcap_md)); #else p = pcap_create_common(ebuf, sizeof(struct pcap_win)); #endif /* HAVE_REMOTE */ if (p == NULL) return (NULL); p->activate_op = pcap_activate_win32; p->can_set_rfmon_op = pcap_can_set_rfmon_win32; return (p); } static int pcap_setfilter_win32_npf(pcap_t *p, struct bpf_program *fp) { struct pcap_win *pw = p->priv; if(PacketSetBpf(p->adapter,fp)==FALSE){ /* * Kernel filter not installed. * * XXX - we don't know whether this failed because: * * the kernel rejected the filter program as invalid, * in which case we should fall back on userland * filtering; * * the kernel rejected the filter program as too big, * in which case we should again fall back on * userland filtering; * * there was some other problem, in which case we * should probably report an error. * * For NPF devices, the Win32 status will be * STATUS_INVALID_DEVICE_REQUEST for invalid * filters, but I don't know what it'd be for * other problems, and for some other devices * it might not be set at all. * * So we just fall back on userland filtering in * all cases. */ /* * install_bpf_program() validates the program. * * XXX - what if we already have a filter in the kernel? */ if (install_bpf_program(p, fp) < 0) return (-1); pw->filtering_in_kernel = 0; /* filtering in userland */ return (0); } /* * It worked. */ pw->filtering_in_kernel = 1; /* filtering in the kernel */ /* * Discard any previously-received packets, as they might have * passed whatever filter was formerly in effect, but might * not pass this filter (BIOCSETF discards packets buffered * in the kernel, so you can lose packets in any case). */ p->cc = 0; return (0); } /* * We filter at user level, since the kernel driver does't process the packets */ static int pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) { if(!fp) { strlcpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf)); return (-1); } /* Install a user level filter */ if (install_bpf_program(p, fp) < 0) { pcap_snprintf(p->errbuf, sizeof(p->errbuf), "setfilter, unable to install the filter: %s", pcap_strerror(errno)); return (-1); } return (0); } static int pcap_getnonblock_win32(pcap_t *p, char *errbuf) { struct pcap_win *pw = p->priv; /* * XXX - if there were a PacketGetReadTimeout() call, we * would use it, and return 1 if the timeout is -1 * and 0 otherwise. */ return (pw->nonblock); } static int pcap_setnonblock_win32(pcap_t *p, int nonblock, char *errbuf) { struct pcap_win *pw = p->priv; int newtimeout; char win_errbuf[PCAP_ERRBUF_SIZE+1]; if (nonblock) { /* * Set the read timeout to -1 for non-blocking mode. */ newtimeout = -1; } else { /* * Restore the timeout set when the device was opened. * (Note that this may be -1, in which case we're not * really leaving non-blocking mode. However, although * the timeout argument to pcap_set_timeout() and * pcap_open_live() is an int, you're not supposed to * supply a negative value, so that "shouldn't happen".) */ newtimeout = p->opt.timeout; } if (!PacketSetReadTimeout(p->adapter, newtimeout)) { pcap_win32_err_to_str(GetLastError(), win_errbuf); pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "PacketSetReadTimeout: %s", win_errbuf); return (-1); } pw->nonblock = (newtimeout == -1); return (0); } static int pcap_add_if_win32(pcap_if_t **devlist, char *name, bpf_u_int32 flags, const char *description, char *errbuf) { pcap_if_t *curdev; npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES]; LONG if_addr_size; int res = 0; if_addr_size = MAX_NETWORK_ADDRESSES; /* * Add an entry for this interface, with no addresses. */ if (add_or_find_if(&curdev, devlist, name, flags, description, errbuf) == -1) { /* * Failure. */ return (-1); } /* * Get the list of addresses for the interface. */ if (!PacketGetNetInfoEx((void *)name, if_addrs, &if_addr_size)) { /* * Failure. * * We don't return an error, because this can happen with * NdisWan interfaces, and we want to supply them even * if we can't supply their addresses. * * We return an entry with an empty address list. */ return (0); } /* * Now add the addresses. */ while (if_addr_size-- > 0) { /* * "curdev" is an entry for this interface; add an entry for * this address to its list of addresses. */ if(curdev == NULL) break; res = add_addr_to_dev(curdev, (struct sockaddr *)&if_addrs[if_addr_size].IPAddress, sizeof (struct sockaddr_storage), (struct sockaddr *)&if_addrs[if_addr_size].SubnetMask, sizeof (struct sockaddr_storage), (struct sockaddr *)&if_addrs[if_addr_size].Broadcast, sizeof (struct sockaddr_storage), NULL, 0, errbuf); if (res == -1) { /* * Failure. */ break; } } return (res); } int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { pcap_if_t *devlist = NULL; int ret = 0; const char *desc; char *AdaptersName; ULONG NameLength; char *name; char our_errbuf[PCAP_ERRBUF_SIZE+1]; /* * Find out how big a buffer we need. * * This call should always return FALSE; if the error is * ERROR_INSUFFICIENT_BUFFER, NameLength will be set to * the size of the buffer we need, otherwise there's a * problem, and NameLength should be set to 0. * * It shouldn't require NameLength to be set, but, * at least as of WinPcap 4.1.3, it checks whether * NameLength is big enough before it checks for a * NULL buffer argument, so, while it'll still do * the right thing if NameLength is uninitialized and * whatever junk happens to be there is big enough * (because the pointer argument will be null), it's * still reading an uninitialized variable. */ NameLength = 0; if (!PacketGetAdapterNames(NULL, &NameLength)) { DWORD last_error = GetLastError(); if (last_error != ERROR_INSUFFICIENT_BUFFER) { pcap_win32_err_to_str(last_error, our_errbuf); pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "PacketGetAdapterNames: %s", our_errbuf); return (-1); } } if (NameLength > 0) AdaptersName = (char*) malloc(NameLength); else { *alldevsp = NULL; return 0; } if (AdaptersName == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot allocate enough memory to list the adapters."); return (-1); } if (!PacketGetAdapterNames(AdaptersName, &NameLength)) { pcap_win32_err_to_str(GetLastError(), our_errbuf); pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "PacketGetAdapterNames: %s", our_errbuf); free(AdaptersName); return (-1); } /* * "PacketGetAdapterNames()" returned a list of * null-terminated ASCII interface name strings, * terminated by a null string, followed by a list * of null-terminated ASCII interface description * strings, terminated by a null string. * This means there are two ASCII nulls at the end * of the first list. * * Find the end of the first list; that's the * beginning of the second list. */ desc = &AdaptersName[0]; while (*desc != '\0' || *(desc + 1) != '\0') desc++; /* * Found it - "desc" points to the first of the two * nulls at the end of the list of names, so the * first byte of the list of descriptions is two bytes * after it. */ desc += 2; /* * Loop over the elements in the first list. */ name = &AdaptersName[0]; while (*name != '\0') { bpf_u_int32 flags = 0; #ifdef HAVE_PACKET_IS_LOOPBACK_ADAPTER /* * Is this a loopback interface? */ if (PacketIsLoopbackAdapter(name)) { /* Yes */ flags |= PCAP_IF_LOOPBACK; } #endif /* * Add an entry for this interface. */ if (pcap_add_if_win32(&devlist, name, flags, desc, errbuf) == -1) { /* * Failure. */ ret = -1; break; } name += strlen(name) + 1; desc += strlen(desc) + 1; } if (ret == -1) { /* * We had an error; free the list we've been constructing. */ if (devlist != NULL) { pcap_freealldevs(devlist); devlist = NULL; } } *alldevsp = devlist; free(AdaptersName); return (ret); } libpcap-1.8.1/extract.h0000644000026300017510000002204713003771737013116 0ustar mcrmcr/* * Copyright (c) 1992, 1993, 1994, 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. */ #ifndef _WIN32 #include #endif /* * Macros to extract possibly-unaligned big-endian integral values. */ #ifdef LBL_ALIGN /* * The processor doesn't natively handle unaligned loads. */ #if defined(__GNUC__) && defined(HAVE___ATTRIBUTE__) && \ (defined(__alpha) || defined(__alpha__) || \ defined(__mips) || defined(__mips__)) /* * This is a GCC-compatible compiler and we have __attribute__, which * we assume that mean we have __attribute__((packed)), and this is * MIPS or Alpha, which has instructions that can help when doing * unaligned loads. * * Declare packed structures containing a uint16_t and a uint32_t, * cast the pointer to point to one of those, and fetch through it; * the GCC manual doesn't appear to explicitly say that * __attribute__((packed)) causes the compiler to generate unaligned-safe * code, but it apppears to do so. * * We do this in case the compiler can generate code using those * instructions to do an unaligned load and pass stuff to "ntohs()" or * "ntohl()", which might be better than than the code to fetch the * bytes one at a time and assemble them. (That might not be the * case on a little-endian platform, such as DEC's MIPS machines and * Alpha machines, where "ntohs()" and "ntohl()" might not be done * inline.) * * We do this only for specific architectures because, for example, * at least some versions of GCC, when compiling for 64-bit SPARC, * generate code that assumes alignment if we do this. * * XXX - add other architectures and compilers as possible and * appropriate. * * HP's C compiler, indicated by __HP_cc being defined, supports * "#pragma unaligned N" in version A.05.50 and later, where "N" * specifies a number of bytes at which the typedef on the next * line is aligned, e.g. * * #pragma unalign 1 * typedef uint16_t unaligned_uint16_t; * * to define unaligned_uint16_t as a 16-bit unaligned data type. * This could be presumably used, in sufficiently recent versions of * the compiler, with macros similar to those below. This would be * useful only if that compiler could generate better code for PA-RISC * or Itanium than would be generated by a bunch of shifts-and-ORs. * * DEC C, indicated by __DECC being defined, has, at least on Alpha, * an __unaligned qualifier that can be applied to pointers to get the * compiler to generate code that does unaligned loads and stores when * dereferencing the pointer in question. * * XXX - what if the native C compiler doesn't support * __attribute__((packed))? How can we get it to generate unaligned * accesses for *specific* items? */ typedef struct { uint16_t val; } __attribute__((packed)) unaligned_uint16_t; typedef struct { uint32_t val; } __attribute__((packed)) unaligned_uint32_t; static inline uint16_t EXTRACT_16BITS(const void *p) { return ((uint16_t)ntohs(((const unaligned_uint16_t *)(p))->val)); } static inline uint32_t EXTRACT_32BITS(const void *p) { return ((uint32_t)ntohl(((const unaligned_uint32_t *)(p))->val)); } static inline uint64_t EXTRACT_64BITS(const void *p) { return ((uint64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 | \ ((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 1)->val)) << 0)); } #else /* have to do it a byte at a time */ /* * This isn't a GCC-compatible compiler, we don't have __attribute__, * or we do but we don't know of any better way with this instruction * set to do unaligned loads, so do unaligned loads of big-endian * quantities the hard way - fetch the bytes one at a time and * assemble them. */ #define EXTRACT_16BITS(p) \ ((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 0)) << 8) | \ ((uint16_t)(*((const uint8_t *)(p) + 1)) << 0))) #define EXTRACT_32BITS(p) \ ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 24) | \ ((uint32_t)(*((const uint8_t *)(p) + 1)) << 16) | \ ((uint32_t)(*((const uint8_t *)(p) + 2)) << 8) | \ ((uint32_t)(*((const uint8_t *)(p) + 3)) << 0))) #define EXTRACT_64BITS(p) \ ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 56) | \ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 48) | \ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 40) | \ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 32) | \ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 24) | \ ((uint64_t)(*((const uint8_t *)(p) + 5)) << 16) | \ ((uint64_t)(*((const uint8_t *)(p) + 6)) << 8) | \ ((uint64_t)(*((const uint8_t *)(p) + 7)) << 0))) #endif /* must special-case unaligned accesses */ #else /* LBL_ALIGN */ /* * The processor natively handles unaligned loads, so we can just * cast the pointer and fetch through it. */ static inline uint16_t EXTRACT_16BITS(const void *p) { return ((uint16_t)ntohs(*(const uint16_t *)(p))); } static inline uint32_t EXTRACT_32BITS(const void *p) { return ((uint32_t)ntohl(*(const uint32_t *)(p))); } static inline uint64_t EXTRACT_64BITS(const void *p) { return ((uint64_t)(((uint64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 | \ ((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0)); } #endif /* LBL_ALIGN */ #define EXTRACT_24BITS(p) \ ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 16) | \ ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ ((uint32_t)(*((const uint8_t *)(p) + 2)) << 0))) #define EXTRACT_40BITS(p) \ ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 32) | \ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 24) | \ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 8) | \ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 0))) #define EXTRACT_48BITS(p) \ ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 40) | \ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 32) | \ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 24) | \ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 16) | \ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \ ((uint64_t)(*((const uint8_t *)(p) + 5)) << 0))) #define EXTRACT_56BITS(p) \ ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 48) | \ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 40) | \ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 32) | \ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 16) | \ ((uint64_t)(*((const uint8_t *)(p) + 5)) << 8) | \ ((uint64_t)(*((const uint8_t *)(p) + 6)) << 0))) /* * Macros to extract possibly-unaligned little-endian integral values. * XXX - do loads on little-endian machines that support unaligned loads? */ #define EXTRACT_LE_8BITS(p) (*(p)) #define EXTRACT_LE_16BITS(p) \ ((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 1)) << 8) | \ ((uint16_t)(*((const uint8_t *)(p) + 0)) << 0))) #define EXTRACT_LE_32BITS(p) \ ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 3)) << 24) | \ ((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \ ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0))) #define EXTRACT_LE_24BITS(p) \ ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \ ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0))) #define EXTRACT_LE_64BITS(p) \ ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 7)) << 56) | \ ((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) | \ ((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) | \ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) | \ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) | \ ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0))) libpcap-1.8.1/pcap_set_buffer_size.3pcap0000644000026300017510000000345613003771737016407 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_SET_BUFFER_SIZE 3PCAP "3 January 2014" .SH NAME pcap_set_buffer_size \- set the buffer size for a not-yet-activated capture handle .SH SYNOPSIS .nf .ft B #include .LP .ft B int pcap_set_buffer_size(pcap_t *p, int buffer_size); .ft .fi .SH DESCRIPTION .B pcap_set_buffer_size() sets the buffer size that will be used on a capture handle when the handle is activated to .IR buffer_size , which is in units of bytes. .SH RETURN VALUE .B pcap_set_buffer_size() returns 0 on success or .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) libpcap-1.8.1/pcap_dump_open.3pcap.in0000644000026300017510000000625713003771737015626 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_DUMP_OPEN 3PCAP "16 February 2015" .SH NAME pcap_dump_open, pcap_dump_fopen \- open a file to which to write packets .SH SYNOPSIS .nf .ft B #include .ft .nf .LP .ft B pcap_dumper_t *pcap_dump_open(pcap_t *p, const char *fname); pcap_dumper_t *pcap_dump_open_append(pcap_t *p, const char *fname); pcap_dumper_t *pcap_dump_fopen(pcap_t *p, FILE *fp); .ft .fi .SH DESCRIPTION .B pcap_dump_open() is called to open a ``savefile'' for writing. .I fname specifies the name of the file to open. The file will have the same format as those used by .BR tcpdump (1) and .BR tcpslice (1). The name "-" is a synonym for .BR stdout . .PP .B pcap_dump_fopen() is called to write data to an existing open stream .IR fp . Note that on Windows, that stream should be opened in binary mode. .PP .I p is a capture or ``savefile'' handle returned by an earlier call to .B pcap_create() and activated by an earlier call to .BR pcap_activate() , or returned by an earlier call to .BR pcap_open_offline() , .BR pcap_open_live() , or .BR pcap_open_dead() . The time stamp precision, link-layer type, and snapshot length from .I p are used as the link-layer type and snapshot length of the output file. .PP .B pcap_dump_open_append() is like .B pcap_dump_open but does not create the file if it does not exist and, if it does already exist, and is a pcap file with the same byte order as the host opening the file, and has the same time stamp precision, link-layer header type, and snapshot length as .IR p , it will write new packets at the end of the file. .SH RETURN VALUES A pointer to a .B pcap_dumper_t structure to use in subsequent .B pcap_dump() and .B pcap_dump_close() calls is returned on success. .B NULL is returned on failure. If .B NULL is returned, .B pcap_geterr(\fIp\fB) can be used to get the error text. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), pcap_open_offline(3PCAP), pcap_open_live(3PCAP), pcap_open_dead(3PCAP), pcap_dump(3PCAP), pcap_dump_close(3PCAP), pcap_geterr(3PCAP), pcap-savefile(@MAN_FILE_FORMATS@) libpcap-1.8.1/README0000644000026300017510000000770513003771737012157 0ustar mcrmcrLIBPCAP 1.x.y www.tcpdump.org Please send inquiries/comments/reports to: tcpdump-workers@lists.tcpdump.org Anonymous Git is available via: git clone git://bpf.tcpdump.org/libpcap Please submit patches by forking the branch on GitHub at http://github.com/the-tcpdump-group/libpcap/tree/master and issuing a pull request. formerly from Lawrence Berkeley National Laboratory Network Research Group ftp://ftp.ee.lbl.gov/old/libpcap-0.4a7.tar.Z This directory contains source code for libpcap, a system-independent interface for user-level packet capture. libpcap provides a portable framework for low-level network monitoring. Applications include network statistics collection, security monitoring, network debugging, etc. Since almost every system vendor provides a different interface for packet capture, and since we've developed several tools that require this functionality, we've created this system-independent API to ease in porting and to alleviate the need for several system-dependent packet capture modules in each application. For some platforms there are README.{system} files that discuss issues with the OS's interface for packet capture on those platforms, such as how to enable support for that interface in the OS, if it's not built in by default. The libpcap interface supports a filtering mechanism based on the architecture in the BSD packet filter. BPF is described in the 1993 Winter Usenix paper ``The BSD Packet Filter: A New Architecture for User-level Packet Capture''. A compressed PostScript version can be found at ftp://ftp.ee.lbl.gov/papers/bpf-usenix93.ps.Z or http://www.tcpdump.org/papers/bpf-usenix93.ps.Z and a gzipped version can be found at http://www.tcpdump.org/papers/bpf-usenix93.ps.gz A PDF version can be found at http://www.tcpdump.org/papers/bpf-usenix93.pdf Although most packet capture interfaces support in-kernel filtering, libpcap utilizes in-kernel filtering only for the BPF interface. On systems that don't have BPF, all packets are read into user-space and the BPF filters are evaluated in the libpcap library, incurring added overhead (especially, for selective filters). Ideally, libpcap would translate BPF filters into a filter program that is compatible with the underlying kernel subsystem, but this is not yet implemented. BPF is standard in 4.4BSD, BSD/OS, NetBSD, FreeBSD, OpenBSD, DragonFly BSD, and Mac OS X; an older, modified and undocumented version is standard in AIX. {DEC OSF/1, Digital UNIX, Tru64 UNIX} uses the packetfilter interface but has been extended to accept BPF filters (which libpcap utilizes). Also, you can add BPF filter support to Ultrix using the kernel source and/or object patches available in: http://www.tcpdump.org/other/bpfext42.tar.Z Linux, in the 2.2 kernel and later kernels, has a "Socket Filter" mechanism that accepts BPF filters; see the README.linux file for information on configuring that option. Note to Linux distributions and *BSD systems that include libpcap: There's now a rule to make a shared library, which should work on Linux and *BSD, among other platforms. It sets the soname of the library to "libpcap.so.1"; this is what it should be, *NOT* libpcap.so.1.x or libpcap.so.1.x.y or something such as that. We've been maintaining binary compatibility between libpcap releases for quite a while; there's no reason to tie a binary linked with libpcap to a particular release of libpcap. Problems, bugs, questions, desirable enhancements, etc. should be sent to the address "tcpdump-workers@lists.tcpdump.org". Bugs, support requests, and feature requests may also be submitted on the GitHub issue tracker for libpcap at https://github.com/the-tcpdump-group/libpcap/issues Source code contributions, etc. should be sent to the email address above or submitted by forking the branch on GitHub at http://github.com/the-tcpdump-group/libpcap/tree/master and issuing a pull request. Current versions can be found at www.tcpdump.org. - The TCPdump team libpcap-1.8.1/pcap-septel.h0000644000026300017510000000077413003771737013664 0ustar mcrmcr/* * pcap-septel.c: Packet capture interface for Intel Septel card * * The functionality of this code attempts to mimic that of pcap-linux as much * as possible. This code is only needed when compiling in the Intel/Septel * card code at the same time as another type of device. * * Authors: Gilbert HOYEK (gil_hoyek@hotmail.com), Elias M. KHOURY * (+961 3 485343); */ pcap_t *septel_create(const char *device, char *ebuf, int *is_ours); int septel_findalldevs(pcap_if_t **devlistp, char *errbuf); libpcap-1.8.1/pcap-bpf.h0000644000026300017510000000436613003771737013140 0ustar mcrmcr/*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * For backwards compatibility. * * Note to OS vendors: do NOT get rid of this file! Some applications * might expect to be able to include . */ #include libpcap-1.8.1/pcap_dump_close.3pcap0000644000026300017510000000277113003771737015362 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_DUMP_CLOSE 3PCAP "3 January 2014" .SH NAME pcap_dump_close \- close a savefile being written to .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B void pcap_dump_close(pcap_dumper_t *p); .ft .fi .SH DESCRIPTION .B pcap_dump_close() closes the ``savefile.'' .SH SEE ALSO pcap(3PCAP), pcap_dump_open(3PCAP), pcap_dump(3PCAP) libpcap-1.8.1/pcap_lookupnet.3pcap0000644000026300017510000000367213003771737015251 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_LOOKUPNET 3PCAP "3 January 2014" .SH NAME pcap_lookupnet \- find the IPv4 network number and netmask for a device .SH SYNOPSIS .nf .ft B #include .ft .LP .nf .ft B char errbuf[PCAP_ERRBUF_SIZE]; .ft .LP .ft B int pcap_lookupnet(const char *device, bpf_u_int32 *netp, .ti +8 bpf_u_int32 *maskp, char *errbuf); .ft .fi .SH DESCRIPTION .B pcap_lookupnet() is used to determine the IPv4 network number and mask associated with the network device .IR device . Both .I netp and .I maskp are .I bpf_u_int32 pointers. .SH RETURN VALUE .B pcap_lookupnet() returns 0 on success and \-1 on failure. If \-1 is returned, .I errbuf is filled in with an appropriate error message. .I errbuf is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. .SH SEE ALSO pcap(3PCAP) libpcap-1.8.1/pcap-sita.html0000644000026300017510000011267713003771737014053 0ustar mcrmcr
A "Distributed Pcap" for
Remote Monitoring LANs & WANs

(Design Notes for the SITA ACN device)
Fulko Hew
SITA INC Canada, Inc.
Revised: October 2, 2007

SUMMARY

    Note: This document is part of the libpcap Git and was derived from 'pcap.3' (circa Aug/07).

    The ACN provides a customized/distributed version of this library that alows SMPs to interact with the various IOPs within the site providing a standard mechanism to capture LAN and WAN message traffic.

    SMP The Supervisory Management Processor where Wireshark (or equivalent) runs in conjuction with a libpcap front-end.
    IOP I/O Processors where the monitored ports exist in conjunction with a custom device driver/libpcap back-end.

    Each IOP will be capable of supporting multiple connections from an SMP enabling monitoring of more than one interface at a time, each through its own seperate connection. The IOP is responsible to ensure and report an error if any attempt is made to monitor the same interface more than once.

    There are three applications that will be supported by the ACN version of libpcap. They each use a slightly different mode for looping/capturing and termination as summarized in the following table:

    Application Capture Termination
    wireshark pcap_dispatch(all packets in one buffer of capture only) pcap_breakloop()
    tshark pcap_dispatch(one buffer of capture only) Since a CTRL-C was used to terminate the application, pcap_breakloop() is never called.
    tcpdump pcap_loop(all packets in the next buffer, and loop forever) pcap_breakloop()

    Note: In all cases, the termination of capturing is always (apparently) followed by pcap_close(). Pcap_breakloop() is only used to stop/suspend looping/processing, and upon close interpretation of the function definitions, it is possible to resume capturing following a pcap_breakloop() without any re-initialization.

    ACN Limitations

    1. Monitoring of backup IOPs is not currently supported.
    2. Ethernet interfaces cannot be monitored in promiscuous mode.

ROUTINES

    The following list of functions is the sub-set of Pcap functions that have been altered/enhanced to support the ACN remote monitoring facility. The remainder of the Pcap functions continue to perform their duties un-altered. Libpcap only supports this mode of operation if it has been configured/compiled for SITA/ACN support.

      pcap_findalldevs
      pcap_freealldevs
      pcap_open_live
      pcap_close
      pcap_setfilter
      pcap_dispatch
      pcap_loop
      pcap_next
      pcap_next_ex
      pcap_stats
    These subroutines have been modified for the ACN specific distributed and remote monitoring ability perform the following basic functions. More detail is provided in the "SMP/IOP Inter-Process Communication Protocol" section.

    pcap_open_live() Used to obtain a packet capture descriptor to look at packets on the network.
    SMP -> IOP The SMP will open a connection to the selected IOP on its 'sniffer' port to ensure it is available. It sends a null terminated string identifying the interface to be monitored.
    IOP -> SMP After any required processing is complete, the IOP will return a null terminated string containing an error message if one occured. If no error occured, a empty string is still returned. Errors are:
    • "Interface (xxx) does not exist."
    • "Interface (xxx) not configured."
    • "Interface (xxx) already being monitored."
    pcap_findalldevs() It constructs a list of network devices that can be opened with pcap_open_live().
    SMP It obtains a list of IOPs currently available (via /etc/hosts).
    SMP -> IOP The SMP will sequentially open a connection to each IOP on its 'sniffer' port to ensure the IOP is available. It sends a null terminated empty interface ID followed by the query request command.
    IOP -> SMP The IOP returns an error response and its list of devices.
    SMP -> IOP The SMP closes the TCP connection with each IOP.
    SMP The SMP adds the received information to its internal structure.
    pcap_freealldevs() Used to free a list allocated by pcap_findalldevs().
    SMP The SMP frees the structure it built as a result of the previous invocation of pcap_findalldevs().
    pcap_dispatch() Used to collect and process packets.
    SMP -> IOP On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), the SMP will pass down the monitor start command and various parameters the IOP should use.
    IOP -> SMP The IOP now sends a stream of captured data.
    SMP The SMP will read the reverse channel of the connection between the SMP and the IOP that provides the captured data (via 'p->read_op' which is 'pcap_read_linux()' until the select() call returns a 'no more data' indication. It will the process (at most) the next 'cnt' packets and invoke the specified callback function for each packet processed.
    IOP The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP.
    pcap_loop() Is similar to pcap_dispatch() except it keeps reading packets until the requested number of packets are processed or an error occurs.
    SMP -> IOP On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), the SMP will pass down the monitor start command and various parameters the IOP should use.
    IOP -> SMP The IOP now sends a stream of captured data.
    SMP The SMP continuously reads the next packet from the reverse channel of the connection between the SMP and the IOP that provides the captured data (via 'p->read_op' which is 'pcap_read_linux()' until 'cnt' packets have been received. The specified callback function will be invoked for each packet received.
    IOP The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP.
    pcap_next() It reads the next packet (by calling pcap_dispatch() with a count of 1) and returns a pointer to the data in that packet.
    SMP -> IOP On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), the SMP will pass down the monitor start command and various parameters the IOP should use.
    IOP -> SMP The IOP now sends a stream of captured data.
    SMP The SMP reads only the next packet from the reverse channel of the connection between the SMP and the IOP that provides the captured data (via calling pcap_dispatch() with a count of 1) and returns a pointer to that data by invoking an internal callback.
    IOP The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP.
    pcap_next_ex() Reads the next packet and returns a success/failure indication.
    SMP -> IOP On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), the SMP will pass down the monitor start command and various parameters the IOP should use.
    IOP -> SMP The IOP now sends a stream of captured data.
    SMP The SMP reads only the next packet from the reverse channel of the connection between the SMP and the IOP that provides the captured data (via calling pcap_dispatch() with a count of 1) and returns seperate pointers to both the packet header and packet data by invoking an internal callback.
    IOP The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP.
    pcap_setfilter() Used to specify a filter program.
    SMP -> IOP The SMP sends a 'set filter' command followed by the BPF commands.
    IOP -> SMP The IOP returns a null terminated error string if it failed to accept the filter. If no error occured, then a NULL terminated empty string is returned instead. Errors are:
    • "Invalid BPF."
    • "Insufficient resources for BPF."
    pcap_stats() Fills in a pcap_stat struct with packet statistics.
    SMP -> IOP The SMP sends a message to the IOP requesting its statistics.
    IOP -> SMP The IOP returns the statistics.
    SMP The SMP fills in the structure provided with the information retrieved from the IOP.
    pcap_close() Closes the file and deallocates resources.
    SMP -> IOP The SMP closes the file descriptor, and if the descriptor is that of the comminucation session with an IOP, it too is terminated.
    IOP If the IOP detects that its communication session with an SMP has closed, it will terminate any monitoring in progress, release any resources and close its end of the session. It will not maintain persistance of any information or prior mode of operation.

SMP/IOP Inter-Process Communication Protocol

  • Communications between an SMP and an IOP consists of a TCP session between an ephemeral port on the SMP and the well known port of 49152 (which is the first available port in the 'dynamic and/or private port' range) on an IOP.

  • Following a TCP open operation the IOP receives a null terminated 'interface ID' string to determine the type of operation that follows:

  • Every command received by an IOP implies a 'stop trace/stop forwarding' operation must occur before executing the received command.

  • A session is closed when the SMP closes the TCP session with the IOP. Obviously monitoring and forwarding is also stopped at that time. Note: All multi-octet entities are sent in network neutral order.


    pcap_findalldevs() SMP -> IOP Open socket (to each IOP), and sends:

    Name/
    Purpose
    Size
    (in bytes)
    Description
    Interface ID 1 A NULL to indicate an an empty 'interface ID'.

    IOP -> SMP Send its (possibly empty) NULL terminated error response string.
    SMP -> IOP Sends the 'interface query request':

    Name/
    Purpose
    Size
    (in bytes)
    Description
    Interface ID 1 A 'Q' (indicating 'interface query request').

    IOP -> SMP The IOP returns a list of sequences of information as defined by the return parameter of this function call (as shown in the following table). Elements are specified by providing an unsigned byte preceeding the actual data that contains length information.

    Notes: Name/
    Purpose
    Size
    (in bytes)
    Description
      length 1 The number of octets in the name field that follows.
    Name 1-255 The name of the interface. The format of the name is an alphabetic string (indicating the type of interface) followed by an optional numeric string (indicating the interface's sequence number). Sequence numbers (if needed) will begin at zero and progress monotonically upwards. (i.e. 'eth0', 'lo', 'wan0', etc.)

    For an IOP, the alphabetic string will be one of: 'eth', 'wan', and 'lo' for Ethernet, WAN ports and the IP loopback device respectively. An IOP currently supports: 'eth0', 'eth1', 'lo', 'wan0' ... 'wan7'.

    Note: IOPs and ACNs will not currently support the concept of 'any' interface.

    length 1 The number of octets in the interface description field that follows.
    Interface Description 0-255 A description of the interface or it may be an empty string. (i.e. 'ALC')
    Interface Type 4 The type of interface as defined in the description for pcap_datalink() (in network neutral order).
    Loopback Flag 1 1 = if the interface is a loopback interface, zero = otherwise.
    count 1 # of address entries that follow. Each entry is a series of bytes in network neutral order. See the parameter definition above for more details.
    Repeated 'count' number of times. length 1 The number of octets in the address field that follows.
    Address 1-255 The address of this interface (in network neutral order).
    length 1 The number of octets in the netmask field that follows.
    Network Mask 0-255 The network mask used on this interface (if applicable) (in network neutral order).
    length 1 The number of octets in the broadcast address field that follows.
    Broadcast Address 0-255 The broadcast address of this interface (if applicable) (in network neutral order).
    length 1 The number of octets in the destination address field that follows.
    Destination Address 0-255 The destination address of this interface (if applicable) (in network neutral order).

    SMP -> IOP Close the socket.
    IOP -> SMP Close the socket.

    pcap_open_live() SMP -> IOP Open socket, and sends:

    Name/
    Purpose
    Size
    (in bytes)
    Description
    Interface ID 'n' 'n' octets containing a NULL terminated interface name string.

    IOP -> SMP Send its NULL terminated error response string.

    pcap_dispatch()
    pcap_loop()
    pcap_next()
    pcap_next_ex()
    SMP -> IOP On the first invocation following a pcap_open_live() or pcap_breakloop() additional information is sent:

    Name/
    Purpose
    Size
    (in bytes)
    Description
    command 1 'M' (indicating 'monitor start')
    snaplen 4 snaplen
    timeout 1 timeout value (in milliseconds)
    promiscuous 1 A flag indicating that the interface being monitored show operate in promiscuous mode. [off(0) / on(NZ)]
    direction 1 A flag indicating the direction of traffic that should be captuted [both(0) / in(1) / out(2)]

    IOP -> SMP Sends captured packets.

    pcap_setfilter() SMP -> IOP At any time, the SMP can issue a set filter command which contains an indicator, a count of the number of statements in the filter, followed by the sequence of filter commands represented as a sequence of C-style structures.

    Name/
    Purpose
    Size
    (in bytes)
    Description
    command 1 'F' (indicating 'filter')
    count 4 The number of command in the Berkeley Packet Filter that follow.
    BPF program 'n' 8 bytes of each command (repeated 'n' times).
    Each command consists of that C-style structure which contains:

    Name/
    Purpose
    Size
    (in bytes)
    Description
    opcode 2 The command's opcode.
    'jt' 1 The 'jump if true' program counter offset.
    'jf' 1 The 'jump if false' program counter offset.
    'k' 4 The 'other' data field.

    Refer to the bpf(4) man page for more details.

    IOP -> SMP In return the IOP will send its (possibly empty) NULL terminated error response string.

    pcap_stats() SMP -> IOP At any time, the SMP can issue a 'retrieve statistics' command which contains:

    Name/
    Purpose
    Size
    (in bytes)
    Description
    command 1 'S' (indicating 'request statistics')

    IOP -> SMP In return the IOP will send:

    Name/
    Purpose
    Size
    (in bytes)
    Description
    ps_recv 4 The number of packets that passed the filter.
    ps_drop 4 The number of packets that were dropped because the input queue was full, regardless of whether they passed the filter.
    ps_ifdrop 4 The number of packets dropped by the network inteface (regardless of whether they would have passed the input filter).


    pcap_close() SMP -> IOP At any time, the SMP can close the TCP session with the IOP.

Interface ID Naming Convention

    Each interface within an IOP will be referred to uniquely. Since an currently contains 8 monitorable WAN ports and a monitorable Ethernet port, the naming convention is:

    Interface # Type Name
    1 WAN wan0
    2 WAN wan1
    3 WAN wan2
    4 WAN wan3
    5 WAN wan4
    6 WAN wan5
    7 WAN wan6
    8 WAN wan7
    9 Ethernet eth0
    10 Ethernet eth1

Packet Trace Data Format

    The format of the trace data that is sent to the SMP follows a portion of the libpcap file format and is summarized here. This format specifies the generic requirements needed to be able to decode packets, but does not cover ACN specifics such as custom MAC addressing and WAN protocol support.

    Although a libpcap file begins with a global header followed by zero or more records for each captured packet, trace data sent to the SMP does NOT begin with a global header. A trace sequence looks like this:

     [Packet Header]   [Packet Data]   [Packet Header]   [Packet Data]   [Packet Header]   [Packet Data]  ...

    Packet Header

      Each captured packet starts with a header that contains the following values (in network neutral order):
       uint32 tv_sec;  /* timestamp seconds */
       uint32 tv_usec; /* timestamp microseconds */
       uint32 caplen;  /* number of octets in the following packet */
       uint32 len;     /* original length of packet on the wire */
      		
      tv_sec The date and time when this packet was captured. This value is in seconds since January 1, 1970 00:00:00 GMT; this is also known as a UN*X time_t. You can use the ANSI C time() function from time.h to get this value, but you might use a more optimized way to get this timestamp value. If this timestamp isn't based on GMT (UTC), use thiszone from the global header for adjustments.
      tv_usec The microseconds when this packet was captured, as an offset to ts_sec. Beware: this value must never reach 1 second (1,000,000), in this case ts_sec must be increased instead!
      caplen The number of bytes actually provided in the capture record. This value should never become larger than len or the snaplen value specified during the capture.
      len The length of the packet "on the wire" when it was captured. If caplen and len differ, the actually saved packet size was limited by the value of snaplen specified during one of the capture directives such as pcap_dispatch().

    Packet Data

      The actual packet data will immediately follow the packet header as a sequence of caplen octets. Depending on the DLT encoding number assigned to the interface, the packet data will contain an additional custom header used to convey WAN port related information.

    ACN Custom Packet Header

      PCAP, Wireshark and Tcpdump enhancements have been added to the ACN to support monitoring of its ports, however each of these facilities were focused on capturing and displaying traffic from LAN interfaces. The SITA extentions to these facilities are used to also provide the ability to capture, filter, and display information from an ACN's WAN ports.

      Although each packet follows the standard libpcap format, since there are two types of interfaces that can be monitored, the format of the data packet varies slightly.

      • For Ethernet (like) devices, the packet format is unchanged from the standard Pcap format.
      • For WAN devices, the packet contains a 5 byte header that preceeds the actual captured data described by the following table:

      Octet Name Mask/Value Definition
      0 Control / Status xxxxxxx0 Transmitted by capture device (see 'Errors' octets)
      xxxxxxx1 Received by capture device
      1xxxxxxx No buffer was available during capture of previous packet.
      1 Signals xxxxxxx1 DSR asserted
      xxxxxx1x DTR asserted
      xxxxx1xx CTS asserted
      xxxx1xxx RTS asserted
      xxx1xxxx DCD asserted
      xx1xxxxx Undefined
      x1xxxxxx Undefined
      1xxxxxxx Undefined
      2 Errors
      (octet 1)
        Tx Rx
      xxxxxxx1 Underrun Framing
      xxxxxx1x CTS Lost Parity
      xxxxx1xx UART Error Collision
      xxxx1xxx Re-Tx Limit Reached Long Frame
      xxx1xxxx Undefined Short Frame
      xx1xxxxx Undefined Undefined
      x1xxxxxx Undefined Undefined
      1xxxxxxx Undefined Undefined
      3 Errors
      (octet 2)
        Tx Rx
      xxxxxxx1 Undefined Non-Octet Aligned
      xxxxxx1x Undefined Abort Received
      xxxxx1xx Undefined CD Lost
      xxxx1xxx Undefined Digital PLL Error
      xxx1xxxx Undefined Overrun
      xx1xxxxx Undefined Frame Length Violation
      x1xxxxxx Undefined CRC Error
      1xxxxxxx Undefined Break Received
      4 Protocol
      0x01 - LAPB (BOP)  
      0x02 - Ethernet 1
      0x03 - Async (Interrupt IO)  
      0x04 - Async (Block IO)  
      0x05 - IPARS  
      0x06 - UTS  
      0x07 - PPP (HDLC)  
      0x08 - SDLC  
      0x09 - Token Ring 1
      0x10 - I2C  
      0x11 - DPM Link  
      0x12 - Frame Relay (BOP)  

      Note 1: Ethernet and Token Ring frames will never be sent as DLT_SITA (with the 5 octet header), but will be sent as their corresponding DLT types instead.

libpcap-1.8.1/sf-pcap-ng.h0000644000026300017510000000264513003771737013401 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. * * sf-pcap-ng.h - pcap-ng-file-format-specific routines * * Used to read pcap-ng savefiles. */ #ifndef sf_pcap_ng_h #define sf_pcap_ng_h extern pcap_t *pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, int *err); #endif libpcap-1.8.1/pcap_lookupdev.3pcap0000644000026300017510000000367113003771737015240 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_LOOKUPDEV 3PCAP "3 January 2014" .SH NAME pcap_lookupdev \- find the default device on which to capture .SH SYNOPSIS .nf .ft B #include .ft .LP .nf .ft B char errbuf[PCAP_ERRBUF_SIZE]; .ft .LP .ft B char *pcap_lookupdev(char *errbuf); .ft .fi .SH DESCRIPTION .B pcap_lookupdev() returns a pointer to a string giving the name of a network device suitable for use with .B pcap_create() and .BR pcap_activate() , or with .BR pcap_open_live() , and with .BR pcap_lookupnet() . If there is an error, .B NULL is returned and .I errbuf is filled in with an appropriate error message. .I errbuf is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), pcap_open_live(3PCAP), pcap_lookupnet(3PCAP) libpcap-1.8.1/Makefile.in0000644000026300017510000005634613003771737013351 0ustar mcrmcr# Copyright (c) 1993, 1994, 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. # # Various configurable paths (remember to edit Makefile.in, not Makefile) # # Top level hierarchy prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ # Pathname of directory to install the configure program bindir = @bindir@ # Pathname of directory to install the include files includedir = @includedir@ # Pathname of directory to install the library libdir = @libdir@ # Pathname of directory to install the man pages mandir = @mandir@ # VPATH srcdir = @srcdir@ VPATH = @srcdir@ # # You shouldn't need to edit anything below. # LD = /usr/bin/ld CC = @CC@ AR = @AR@ LN_S = @LN_S@ MKDEP = @MKDEP@ CCOPT = @V_CCOPT@ INCLS = -I. @V_INCLS@ DEFS = -DBUILDING_PCAP @DEFS@ @V_DEFS@ ADDLOBJS = @ADDLOBJS@ ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@ LIBS = @LIBS@ CROSSFLAGS= CFLAGS = @CFLAGS@ ${CROSSFLAGS} LDFLAGS = @LDFLAGS@ ${CROSSFLAGS} DYEXT = @DYEXT@ V_RPATH_OPT = @V_RPATH_OPT@ DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ PROG=libpcap # Standard CFLAGS FULL_CFLAGS = $(CCOPT) $(INCLS) $(DEFS) $(CFLAGS) INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ RANLIB = @RANLIB@ LEX = @LEX@ YACC = @YACC@ # Explicitly define compilation rule since SunOS 4's make doesn't like gcc. # Also, gcc does not remove the .o before forking 'as', which can be a # problem if you don't own the file but can write to the directory. .c.o: @rm -f $@ $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @BT_MONITOR_SRC@ @NETFILTER_SRC@ @DBUS_SRC@ FSRC = @V_FINDALLDEVS@ SSRC = @SSRC@ CSRC = pcap.c inet.c fad-helpers.c gencode.c optimize.c nametoaddr.c \ etherent.c savefile.c sf-pcap.c sf-pcap-ng.c pcap-common.c \ bpf_image.c bpf_dump.c GENSRC = scanner.c grammar.c bpf_filter.c version.c LIBOBJS = @LIBOBJS@ SRC = $(PSRC) $(FSRC) $(CSRC) $(SSRC) $(GENSRC) # We would like to say "OBJ = $(SRC:.c=.o)" but Ultrix's make cannot # hack the extra indirection OBJ = $(PSRC:.c=.o) $(FSRC:.c=.o) $(CSRC:.c=.o) $(SSRC:.c=.o) $(GENSRC:.c=.o) $(LIBOBJS) PUBHDR = \ pcap.h \ pcap-bpf.h \ pcap-namedb.h \ pcap/bpf.h \ pcap/bluetooth.h \ pcap/can_socketcan.h \ pcap/dlt.h \ pcap/export-defs.h \ pcap/ipnet.h \ pcap/namedb.h \ pcap/nflog.h \ pcap/pcap.h \ pcap/sll.h \ pcap/vlan.h \ pcap/usb.h HDR = $(PUBHDR) \ arcnet.h \ atmuni31.h \ ethertype.h \ extract.h \ gencode.h \ ieee80211.h \ llc.h \ nametoaddr.h \ nlpid.h \ pcap-common.h \ pcap-int.h \ pcap-stdinc.h \ portability.h \ ppp.h \ sf-pcap.h \ sf-pcap-ng.h \ sunatmpos.h TESTS = \ @VALGRINDTEST@ \ capturetest \ can_set_rfmon_test \ filtertest \ findalldevstest \ opentest \ reactivatetest \ selpolltest TESTS_SRC = \ tests/valgrindtest.c \ tests/capturetest.c \ tests/can_set_rfmon_test.c \ tests/filtertest.c \ tests/findalldevstest.c \ tests/opentest.c \ tests/reactivatetest.c \ tests/selpolltest.c GENHDR = \ scanner.h grammar.h pcap_version.h TAGFILES = \ $(SRC) $(HDR) CLEANFILES = $(OBJ) libpcap.* $(TESTS) \ $(PROG)-`cat $(srcdir)/VERSION`.tar.gz $(GENSRC) $(GENHDR) \ lex.yy.c pcap-config MAN1 = pcap-config.1 MAN3PCAP_EXPAND = \ pcap.3pcap.in \ pcap_compile.3pcap.in \ pcap_datalink.3pcap.in \ pcap_dump_open.3pcap.in \ pcap_get_tstamp_precision.3pcap.in \ pcap_list_datalinks.3pcap.in \ pcap_list_tstamp_types.3pcap.in \ pcap_open_dead.3pcap.in \ pcap_open_offline.3pcap.in \ pcap_set_tstamp_precision.3pcap.in \ pcap_set_tstamp_type.3pcap.in MAN3PCAP_NOEXPAND = \ pcap_activate.3pcap \ pcap_breakloop.3pcap \ pcap_can_set_rfmon.3pcap \ pcap_close.3pcap \ pcap_create.3pcap \ pcap_datalink_name_to_val.3pcap \ pcap_datalink_val_to_name.3pcap \ pcap_dump.3pcap \ pcap_dump_close.3pcap \ pcap_dump_file.3pcap \ pcap_dump_flush.3pcap \ pcap_dump_ftell.3pcap \ pcap_file.3pcap \ pcap_fileno.3pcap \ pcap_findalldevs.3pcap \ pcap_freecode.3pcap \ pcap_get_selectable_fd.3pcap \ pcap_geterr.3pcap \ pcap_inject.3pcap \ pcap_is_swapped.3pcap \ pcap_lib_version.3pcap \ pcap_lookupdev.3pcap \ pcap_lookupnet.3pcap \ pcap_loop.3pcap \ pcap_major_version.3pcap \ pcap_next_ex.3pcap \ pcap_offline_filter.3pcap \ pcap_open_live.3pcap \ pcap_set_buffer_size.3pcap \ pcap_set_datalink.3pcap \ pcap_set_immediate_mode.3pcap \ pcap_set_promisc.3pcap \ pcap_set_rfmon.3pcap \ pcap_set_snaplen.3pcap \ pcap_set_timeout.3pcap \ pcap_setdirection.3pcap \ pcap_setfilter.3pcap \ pcap_setnonblock.3pcap \ pcap_snapshot.3pcap \ pcap_stats.3pcap \ pcap_statustostr.3pcap \ pcap_strerror.3pcap \ pcap_tstamp_type_name_to_val.3pcap \ pcap_tstamp_type_val_to_name.3pcap MAN3PCAP = $(MAN3PCAP_NOEXPAND) $(MAN3PCAP_EXPAND:.in=) MANFILE = \ pcap-savefile.manfile.in MANMISC = \ pcap-filter.manmisc.in \ pcap-linktype.manmisc.in \ pcap-tstamp.manmisc.in EXTRA_DIST = \ $(TESTS_SRC) \ CHANGES \ ChmodBPF/ChmodBPF \ ChmodBPF/StartupParameters.plist \ CREDITS \ CMakeLists.txt \ GenVersion.bat \ INSTALL.txt \ LICENSE \ Makefile.in \ Makefile-devel-adds \ README \ README.aix \ README.dag \ README.hpux \ README.linux \ README.macosx \ README.septel \ README.sita \ README.tru64 \ README.Win32 \ SUNOS4/nit_if.o.sparc \ SUNOS4/nit_if.o.sun3 \ SUNOS4/nit_if.o.sun4c.4.0.3c \ TODO \ VERSION \ aclocal.m4 \ bpf/net/bpf_filter.c \ chmod_bpf \ cmakeconfig.h.in \ cmake/preconfigure.cmake \ config/have_siocglifconf.c \ config.guess \ config.h.in \ config.sub \ configure \ configure.ac \ dlpisubs.c \ dlpisubs.h \ fad-getad.c \ fad-gifc.c \ fad-glifc.c \ fad-helpers.c \ gen_version_c.sh \ gen_version_header.sh \ grammar.y \ install-sh \ lbl/os-aix4.h \ lbl/os-aix7.h \ lbl/os-hpux11.h \ lbl/os-osf4.h \ lbl/os-osf5.h \ lbl/os-solaris2.h \ lbl/os-sunos4.h \ lbl/os-ultrix4.h \ missing/getopt.c \ missing/getopt.h \ missing/snprintf.c \ missing/strtok_r.c \ missing/win_snprintf.c \ mkdep \ msdos/bin2c.c \ msdos/common.dj \ msdos/makefile \ msdos/makefile.dj \ msdos/makefile.wc \ msdos/ndis2.c \ msdos/ndis2.h \ msdos/ndis_0.asm \ msdos/pkt_rx0.asm \ msdos/pkt_rx1.s \ msdos/pktdrvr.c \ msdos/pktdrvr.h \ msdos/readme.dos \ org.tcpdump.chmod_bpf.plist \ pcap-bpf.c \ pcap-bt-linux.c \ pcap-bt-linux.h \ pcap-bt-monitor-linux.c \ pcap-bt-monitor-linux.h \ pcap-config.in \ pcap-dag.c \ pcap-dag.h \ pcap-dbus.c \ pcap-dbus.h \ pcap-dlpi.c \ pcap-dos.c \ pcap-dos.h \ pcap-enet.c \ pcap-int.h \ pcap-libdlpi.c \ pcap-linux.c \ pcap-namedb.h \ pcap-new.c \ pcap-netfilter-linux.c \ pcap-netfilter-linux.h \ pcap-nit.c \ pcap-null.c \ pcap-pf.c \ pcap-rpcap.c \ pcap-rpcap.h \ pcap-septel.c \ pcap-septel.h \ pcap-sita.h \ pcap-sita.c \ pcap-sita.html \ pcap-snf.c \ pcap-snf.h \ pcap-snit.c \ pcap-snoop.c \ pcap-tc.c \ pcap-tc.h \ pcap-usb-linux.c \ pcap-usb-linux.h \ pcap-win32.c \ remote-ext.h \ sockutils.c \ sockutils.h \ scanner.l \ tests/CMakeLists.txt \ pcap_version.h.in \ Win32/Include/Gnuc.h \ Win32/Include/net/if.h \ Win32/Prj/wpcap.sln \ Win32/Prj/wpcap.vcxproj \ Win32/Prj/wpcap.vcxproj.filters all: libpcap.a shared pcap-config libpcap.a: $(OBJ) @rm -f $@ $(AR) rc $@ $(OBJ) $(ADDLARCHIVEOBJS) $(RANLIB) $@ shared: libpcap.$(DYEXT) libpcap.so: $(OBJ) @rm -f $@ VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ @V_SHLIB_CMD@ @V_SHLIB_OPT@ @V_SONAME_OPT@$@.$$MAJOR_VER $(LDFLAGS) \ -o $@.$$VER $(OBJ) $(ADDLOBJS) $(LIBS) # # The following rule succeeds, but the result is untested. # # In Mac OS X, the libpcap dylib has the name "libpcap.A.dylib", with # its full path as the install_name, and with the compatibility and # current version both set to 1. The compatibility version is set to # 1 so that programs built with a newer version of the library will run # against older versions; multi-platform software probably will fail if # it uses APIs added in the newer version, but Mac OS X-specific software # will use weak linking and check at run time whether those APIs are # available. # # We also use "A" as the major version, and 1 as the compatibility version, # but set the current version to the value in VERSION, with any non-numeric # stuff stripped off (the compatibility and current version must be of the # form X[.Y[.Z]], with Y and Z possibly absent, and with all components # numeric). # libpcap.dylib: $(OBJ) rm -f libpcap*.dylib VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=A; \ COMPAT_VER=1; \ CURRENT_VER=`sed 's/[^0-9.].*$$//' $(srcdir)/VERSION`; \ $(CC) -dynamiclib -undefined error $(LDFLAGS) \ -o libpcap.$$VER.dylib $(OBJ) $(ADDLOBJS) $(LIBS) \ -install_name $(libdir)/libpcap.$$MAJOR_VER.dylib \ -compatibility_version $$COMPAT_VER \ -current_version $$CURRENT_VER # # The HP-UX linker manual says that the convention for a versioned library # is libXXX.{number}, not libXXX.sl.{number}. That appears to be the case # on at least one HP-UX 11.00 system; libXXX.sl is a symlink to # libXXX.{number}. # # The manual also says "library-level versioning" (think "sonames") was # added in HP-UX 10.0. # # XXX - this assumes we're using the HP linker, rather than the GNU # linker, even with GCC. # libpcap.sl: $(OBJ) @MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ rm -f libpcap.$$MAJOR_VER MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ ld -b $(LDFLAGS) -o libpcap.$$MAJOR_VER +h libpcap.$$MAJOR_VER \ $(OBJ) $(ADDLOBJS) $(LIBS) # # AIX is different from everybody else. A shared library is an archive # library with one or more shared-object components. We still build a # normal static archive library on AIX, for the benefit of the traditional # scheme of building libpcap and tcpdump in subdirectories of the # same directory, with tcpdump statically linked with the libpcap # in question, but we also build a shared library as "libpcap.shareda" # and install *it*, rather than the static library, as "libpcap.a". # libpcap.shareda: $(OBJ) @rm -f $@ shr.o $(CC) @V_SHLIB_OPT@ -o shr.o $(OBJ) $(ADDLOBJS) $(LDFLAGS) $(LIBS) $(AR) rc $@ shr.o # # For platforms that don't support shared libraries (or on which we # don't support shared libraries). # libpcap.none: scanner.c: $(srcdir)/scanner.l $(LEX) -P pcap_ --header-file=scanner.h --nounput -o scanner.c $< scanner.h: scanner.c ## Recover from the removal of $@ @if test -f $@; then :; else \ rm -f scanner.c; \ $(MAKE) $(MAKEFLAGS) scanner.c; \ fi scanner.o: scanner.c grammar.h $(CC) $(FULL_CFLAGS) -c scanner.c pcap.o: pcap_version.h grammar.c: $(srcdir)/grammar.y $(YACC) -p pcap_ -o grammar.c -d $< grammar.h: grammar.c ## Recover from the removal of $@ @if test -f $@; then :; else \ rm -f grammar.c; \ $(MAKE) $(MAKEFLAGS) grammar.c; \ fi grammar.o: grammar.c $(CC) $(FULL_CFLAGS) -c grammar.c gencode.o: $(srcdir)/gencode.c grammar.h scanner.h $(CC) $(FULL_CFLAGS) -c $(srcdir)/gencode.c version.o: version.c $(CC) $(FULL_CFLAGS) -c version.c snprintf.o: $(srcdir)/missing/snprintf.c $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/snprintf.c strtok_r.o: $(srcdir)/missing/strtok_r.c $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strtok_r.c version.c: $(srcdir)/VERSION $(srcdir)/gen_version_c.sh # # Older programs import this if they want to show the # libpcap version number, rather than calling # pcap_lib_version(), so we need to export it. # @rm -f $@ $(srcdir)/gen_version_c.sh $(srcdir)/VERSION $@ pcap_version.h: $(srcdir)/VERSION $(srcdir)/pcap_version.h.in $(srcdir)/gen_version_header.sh @rm -f $@ $(srcdir)/gen_version_header.sh $(srcdir)/VERSION $(srcdir)/pcap_version.h.in $@ bpf_filter.c: $(srcdir)/bpf/net/bpf_filter.c rm -f bpf_filter.c ln -s $(srcdir)/bpf/net/bpf_filter.c bpf_filter.c bpf_filter.o: bpf_filter.c $(CC) $(FULL_CFLAGS) -c bpf_filter.c # # Generate the pcap-config script. # # Some Makes, e.g. AIX Make and Solaris Make, can't handle "--file=$@.tmp:$<"; # for example, the Solaris 9 make man page says # # Because make assigns $< and $* as it would for implicit rules # (according to the suffixes list and the directory contents), # they may be unreliable when used within explicit target entries. # # and this is an explicit target entry. # # Therefore, instead of using $<, we explicitly put in $(srcdir)/pcap-config.in. # pcap-config: $(srcdir)/pcap-config.in ./config.status @rm -f $@ $@.tmp ./config.status --file=$@.tmp:$(srcdir)/pcap-config.in mv $@.tmp $@ chmod a+x $@ # # Test programs - not built by default, and not installed. # tests: $(TESTS) capturetest: tests/capturetest.c libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o capturetest $(srcdir)/tests/capturetest.c libpcap.a $(LIBS) can_set_rfmon_test: tests/can_set_rfmon_test.c libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o can_set_rfmon_test $(srcdir)/tests/can_set_rfmon_test.c libpcap.a $(LIBS) filtertest: tests/filtertest.c libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o filtertest $(srcdir)/tests/filtertest.c libpcap.a $(LIBS) findalldevstest: tests/findalldevstest.c libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o findalldevstest $(srcdir)/tests/findalldevstest.c libpcap.a $(LIBS) opentest: tests/opentest.c libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o opentest $(srcdir)/tests/opentest.c libpcap.a $(LIBS) reactivatetest: tests/reactivatetest.c libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o reactivatetest $(srcdir)/tests/reactivatetest.c libpcap.a $(LIBS) selpolltest: tests/selpolltest.c libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o selpolltest $(srcdir)/tests/selpolltest.c libpcap.a $(LIBS) valgrindtest: tests/valgrindtest.c libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o valgrindtest $(srcdir)/tests/valgrindtest.c libpcap.a $(LIBS) install: install-shared install-archive pcap-config [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) [ -d $(DESTDIR)$(includedir) ] || \ (mkdir -p $(DESTDIR)$(includedir); chmod 755 $(DESTDIR)$(includedir)) [ -d $(DESTDIR)$(includedir)/pcap ] || \ (mkdir -p $(DESTDIR)$(includedir)/pcap; chmod 755 $(DESTDIR)$(includedir)/pcap) [ -d $(DESTDIR)$(mandir)/man1 ] || \ (mkdir -p $(DESTDIR)$(mandir)/man1; chmod 755 $(DESTDIR)$(mandir)/man1) [ -d $(DESTDIR)$(mandir)/man3 ] || \ (mkdir -p $(DESTDIR)$(mandir)/man3; chmod 755 $(DESTDIR)$(mandir)/man3) [ -d $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@ ] || \ (mkdir -p $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@) [ -d $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@ ] || \ (mkdir -p $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@) for i in $(PUBHDR); do \ $(INSTALL_DATA) $(srcdir)/$$i \ $(DESTDIR)$(includedir)/$$i; done [ -d $(DESTDIR)$(bindir) ] || \ (mkdir -p $(DESTDIR)$(bindir); chmod 755 $(DESTDIR)$(bindir)) $(INSTALL_PROGRAM) pcap-config $(DESTDIR)$(bindir)/pcap-config for i in $(MAN1); do \ $(INSTALL_DATA) $(srcdir)/$$i \ $(DESTDIR)$(mandir)/man1/$$i; done for i in $(MAN3PCAP_NOEXPAND); do \ $(INSTALL_DATA) $(srcdir)/$$i \ $(DESTDIR)$(mandir)/man3/$$i; done for i in $(MAN3PCAP_EXPAND:.in=); do \ $(INSTALL_DATA) $$i \ $(DESTDIR)$(mandir)/man3/$$i; done (cd $(DESTDIR)$(mandir)/man3 && \ rm -f pcap_datalink_val_to_description.3pcap && \ $(LN_S) pcap_datalink_val_to_name.3pcap \ pcap_datalink_val_to_description.3pcap && \ rm -f pcap_dump_fopen.3pcap && \ $(LN_S) pcap_dump_open.3pcap pcap_dump_fopen.3pcap && \ rm -f pcap_freealldevs.3pcap && \ $(LN_S) pcap_findalldevs.3pcap pcap_freealldevs.3pcap && \ rm -f pcap_perror.3pcap && \ $(LN_S) pcap_geterr.3pcap pcap_perror.3pcap && \ rm -f pcap_sendpacket.3pcap && \ $(LN_S) pcap_inject.3pcap pcap_sendpacket.3pcap && \ rm -f pcap_free_datalinks.3pcap && \ $(LN_S) pcap_list_datalinks.3pcap pcap_free_datalinks.3pcap && \ rm -f pcap_free_tstamp_types.3pcap && \ $(LN_S) pcap_list_tstamp_types.3pcap pcap_free_tstamp_types.3pcap && \ rm -f pcap_dispatch.3pcap && \ $(LN_S) pcap_loop.3pcap pcap_dispatch.3pcap && \ rm -f pcap_minor_version.3pcap && \ $(LN_S) pcap_major_version.3pcap pcap_minor_version.3pcap && \ rm -f pcap_next.3pcap && \ $(LN_S) pcap_next_ex.3pcap pcap_next.3pcap && \ rm -f pcap_open_dead_with_tstamp_precision.3pcap && \ $(LN_S) pcap_open_dead.3pcap \ pcap_open_dead_with_tstamp_precision.3pcap && \ rm -f pcap_open_offline_with_tstamp_precision.3pcap && \ $(LN_S) pcap_open_offline.3pcap pcap_open_offline_with_tstamp_precision.3pcap && \ rm -f pcap_fopen_offline.3pcap && \ $(LN_S) pcap_open_offline.3pcap pcap_fopen_offline.3pcap && \ rm -f pcap_fopen_offline_with_tstamp_precision.3pcap && \ $(LN_S) pcap_open_offline.3pcap pcap_fopen_offline_with_tstamp_precision.3pcap && \ rm -f pcap_tstamp_type_val_to_description.3pcap && \ $(LN_S) pcap_tstamp_type_val_to_name.3pcap pcap_tstamp_type_val_to_description.3pcap && \ rm -f pcap_getnonblock.3pcap && \ $(LN_S) pcap_setnonblock.3pcap pcap_getnonblock.3pcap) for i in $(MANFILE); do \ $(INSTALL_DATA) `echo $$i | sed 's/.manfile.in/.manfile/'` \ $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done for i in $(MANMISC); do \ $(INSTALL_DATA) `echo $$i | sed 's/.manmisc.in/.manmisc/'` \ $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@/`echo $$i | sed 's/.manmisc.in/.@MAN_MISC_INFO@/'`; done install-shared: install-shared-$(DYEXT) install-shared-so: libpcap.so [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ $(INSTALL_PROGRAM) libpcap.so.$$VER $(DESTDIR)$(libdir)/libpcap.so.$$VER; \ ln -sf libpcap.so.$$VER $(DESTDIR)$(libdir)/libpcap.so.$$MAJOR_VER; \ ln -sf libpcap.so.$$MAJOR_VER $(DESTDIR)$(libdir)/libpcap.so install-shared-dylib: libpcap.dylib [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=A; \ $(INSTALL_PROGRAM) libpcap.$$VER.dylib $(DESTDIR)$(libdir)/libpcap.$$VER.dylib; \ ln -sf libpcap.$$VER.dylib $(DESTDIR)$(libdir)/libpcap.$$MAJOR_VER.dylib; \ ln -sf libpcap.$$MAJOR_VER.dylib $(DESTDIR)$(libdir)/libpcap.dylib install-shared-sl: libpcap.sl [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ $(INSTALL_PROGRAM) libpcap.$$MAJOR_VER $(DESTDIR)$(libdir) ln -sf libpcap.$$MAJOR_VER $(DESTDIR)$(libdir)/libpcap.sl install-shared-shareda: libpcap.shareda # # AIX shared libraries are weird. They're archive libraries # with one or more shared object components. # [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) $(INSTALL_PROGRAM) libpcap.shareda $(DESTDIR)$(libdir)/libpcap.a install-shared-none: install-archive: install-archive-$(DYEXT) install-archive-so install-archive-dylib install-archive-sl install-archive-none: libpcap.a # # Most platforms have separate suffixes for shared and # archive libraries, so we install both. # [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) $(INSTALL_DATA) libpcap.a $(DESTDIR)$(libdir)/libpcap.a $(RANLIB) $(DESTDIR)$(libdir)/libpcap.a install-archive-shareda: # # AIX, however, doesn't, so we don't install the archive # library on AIX. # uninstall: uninstall-shared rm -f $(DESTDIR)$(libdir)/libpcap.a for i in $(PUBHDR); do \ rm -f $(DESTDIR)$(includedir)/$$i; done -rmdir $(DESTDIR)$(includedir)/pcap rm -f $(DESTDIR)/$(bindir)/pcap-config for i in $(MAN1); do \ rm -f $(DESTDIR)$(mandir)/man1/$$i; done for i in $(MAN3PCAP); do \ rm -f $(DESTDIR)$(mandir)/man3/$$i; done rm -f $(DESTDIR)$(mandir)/man3/pcap_datalink_val_to_description.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_dump_fopen.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_freealldevs.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_perror.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_sendpacket.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_free_datalinks.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_free_tstamp_types.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_dispatch.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_minor_version.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_next.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_open_dead_with_tstamp_precision.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_open_offline_with_tstamp_precision.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_fopen_offline.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_fopen_offline_with_tstamp_precision.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_getnonblock.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_tstamp_type_val_to_description.3pcap for i in $(MANFILE); do \ rm -f $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done for i in $(MANMISC); do \ rm -f $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@/`echo $$i | sed 's/.manmisc.in/.@MAN_MISC_INFO@/'`; done uninstall-shared: uninstall-shared-$(DYEXT) uninstall-shared-so: VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ rm -f $(DESTDIR)$(libdir)/libpcap.so.$$VER; \ rm -f $(DESTDIR)$(libdir)/libpcap.so.$$MAJOR_VER; \ rm -f $(DESTDIR)$(libdir)/libpcap.so uninstall-shared-dylib: VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=A; \ rm -f $(DESTDIR)$(libdir)/libpcap.$$VER.dylib; \ rm -f $(DESTDIR)$(libdir)/libpcap.$$MAJOR_VER.dylib; \ rm -f $(DESTDIR)$(libdir)/libpcap.dylib uninstall-shared-sl: MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ rm -f $(DESTDIR)$(libdir)/libpcap.$$MAJOR_VER; \ rm -f $(DESTDIR)$(libdir)/libpcap.sl uninstall-shared-shareda: rm -f $(DESTDIR)$(libdir)/libpcap.a uninstall-shared-none: clean: rm -f $(CLEANFILES) distclean: clean rm -f Makefile config.cache config.log config.status \ config.h gnuc.h net os-proto.h bpf_filter.c pcap-config \ stamp-h stamp-h.in rm -f $(MAN3PCAP_EXPAND:.in=) $(MANFILE:.in=) $(MANMISC:.in=) rm -rf autom4te.cache extags: $(TAGFILES) ctags $(TAGFILES) tags: $(TAGFILES) ctags -wtd $(TAGFILES) releasetar: @cwd=`pwd` ; dir=`basename $$cwd` ; name=$(PROG)-`cat VERSION` ; \ mkdir $$name; \ tar cf - $(CSRC) $(HDR) $(MAN1) $(MAN3PCAP_EXPAND) \ $(MAN3PCAP_NOEXPAND) $(MANFILE) $(MANMISC) $(EXTRA_DIST) | \ (cd $$name; tar xf -); \ tar -c -z -f $$name.tar.gz $$name; \ rm -rf $$name depend: $(GENSRC) $(GENHDR) bpf_filter.c $(MKDEP) -c $(CC) -m $(CFLAGS) $(DEPENDENCY_CFLAG) $(DEFS) $(INCLS) $(SRC) libpcap-1.8.1/README.macosx0000644000026300017510000000670113003771737013443 0ustar mcrmcrAs with other systems using BPF, Mac OS X allows users with read access to the BPF devices to capture packets with libpcap and allows users with write access to the BPF devices to send packets with libpcap. On some systems that use BPF, the BPF devices live on the root file system, and the permissions and/or ownership on those devices can be changed to give users other than root permission to read or write those devices. On newer versions of FreeBSD, the BPF devices live on devfs, and devfs can be configured to set the permissions and/or ownership of those devices to give users other than root permission to read or write those devices. On Mac OS X, the BPF devices live on devfs, but the OS X version of devfs is based on an older (non-default) FreeBSD devfs, and that version of devfs cannot be configured to set the permissions and/or ownership of those devices. Therefore, we supply: a "startup item" for older versions of Mac OS X; a launchd daemon for Tiger and later versions of Mac OS X; Both of them will change the ownership of the BPF devices so that the "admin" group owns them, and will change the permission of the BPF devices to rw-rw----, so that all users in the "admin" group - i.e., all users with "Allow user to administer this computer" turned on - have both read and write access to them. The startup item is in the ChmodBPF directory in the source tree. A /Library/StartupItems directory should be created if it doesn't already exist, and the ChmodBPF directory should be copied to the /Library/StartupItems directory (copy the entire directory, so that there's a /Library/StartupItems/ChmodBPF directory, containing all the files in the source tree's ChmodBPF directory; don't copy the individual items in that directory to /Library/StartupItems). The ChmodBPF directory, and all files under it, must be owned by root. Installing the files won't immediately cause the startup item to be executed; it will be executed on the next reboot. To change the permissions before the reboot, run sudo SystemStarter start ChmodBPF The launchd daemon is the chmod_bpf script, plus the org.tcpdump.chmod_bpf.plist launchd plist file. chmod_bpf should be installed in /usr/local/bin/chmod_bpf, and org.tcpdump.chmod_bpf.plist should be installed in /Library/LaunchDaemons. chmod_bpf, and org.tcpdump.chmod_bpf.plist, must be owned by root. Installing the script and plist file won't immediately cause the script to be executed; it will be executed on the next reboot. To change the permissions before the reboot, run sudo /usr/local/bin/chmod_bpf or sudo launchctl load /Library/LaunchDaemons/org.tcpdump.chmod_bpf.plist If you want to give a particular user permission to access the BPF devices, rather than giving all administrative users permission to access them, you can have the ChmodBPF/ChmodBPF script change the ownership of /dev/bpf* without changing the permissions. If you want to give a particular user permission to read and write the BPF devices and give the administrative users permission to read but not write the BPF devices, you can have the script change the owner to that user, the group to "admin", and the permissions to rw-r-----. Other possibilities are left as an exercise for the reader. (NOTE: due to a bug in Snow Leopard, if you change the permissions not to grant write permission to everybody who should be allowed to capture traffic, non-root users who cannot open the BPF devices for writing will not be able to capture outgoing packets.) libpcap-1.8.1/README.dag0000644000026300017510000001221413003771737012700 0ustar mcrmcr The following instructions apply if you have a Linux or FreeBSD platform and want libpcap to support the DAG range of passive network monitoring cards from Endace (http://www.endace.com, see below for further contact details). 1) Install and build the DAG software distribution by following the instructions supplied with that package. Current Endace customers can download the DAG software distibution from https://www.endace.com 2) Configure libcap. To allow the 'configure' script to locate the DAG software distribution use the '--with-dag' option: ./configure --with-dag=DIR Where DIR is the root of the DAG software distribution, for example /var/src/dag. If the DAG software is correctly detected 'configure' will report: checking whether we have DAG API... yes If 'configure' reports that there is no DAG API, the directory may have been incorrectly specified or the DAG software was not built before configuring libpcap. See also the libpcap INSTALL.txt file for further libpcap configuration options. Building libpcap at this stage will include support for both the native packet capture stream (linux or bpf) and for capturing from DAG cards. To build libpcap with only DAG support specify the capture type as 'dag' when configuring libpcap: ./configure --with-dag=DIR --with-pcap=dag Applications built with libpcap configured in this way will only detect DAG cards and will not capture from the native OS packet stream. ---------------------------------------------------------------------- Libpcap when built for DAG cards against dag-2.5.1 or later releases: Timeouts are supported. pcap_dispatch() will return after to_ms milliseconds regardless of how many packets are received. If to_ms is zero pcap_dispatch() will block waiting for data indefinitely. pcap_dispatch() will block on and process a minimum of 64kB of data (before filtering) for efficiency. This can introduce high latencies on quiet interfaces unless a timeout value is set. The timeout expiring will override the 64kB minimum causing pcap_dispatch() to process any available data and return. pcap_setnonblock is supported. When nonblock is set, pcap_dispatch() will check once for available data, process any data available up to count, then return immediately. pcap_findalldevs() is supported, e.g. dag0, dag1... Some DAG cards can provide more than one 'stream' of received data. This can be data from different physical ports, or separated by filtering or load balancing mechanisms. Receive streams have even numbers, e.g. dag0:0, dag0:2 etc. Specifying transmit streams for capture is not supported. pcap_setfilter() is supported, BPF programs run in userspace. pcap_setdirection() is not supported. Only received traffic is captured. DAG cards normally do not have IP or link layer addresses assigned as they are used to passively monitor links. pcap_breakloop() is supported. pcap_datalink() and pcap_list_datalinks() are supported. The DAG card does not attempt to set the correct datalink type automatically where more than one type is possible. pcap_stats() is supported. ps_drop is the number of packets dropped due to RX stream buffer overflow, this count is before filters are applied (it will include packets that would have been dropped by the filter). The RX stream buffer size is user configurable outside libpcap, typically 16-512MB. pcap_get_selectable_fd() is not supported, as DAG cards do not support poll/select methods. pcap_inject() and pcap_sendpacket() are not supported. Some DAG cards now support capturing to multiple virtual interfaces, called streams. Capture streams have even numbers. These are available via libpcap as separate interfaces, e.g. dag0:0, dag0:2, dag0:4 etc. dag0:0 is the same as dag0. These are visible via pcap_findalldevs(). libpcap now does NOT set the card's hardware snaplen (slen). This must now be set using the appropriate DAG coniguration program, e.g. dagthree, dagfour, dagsix, dagconfig. This is because the snaplen is currently shared between all of the streams. In future this may change if per-stream slen is implemented. DAG cards by default capture entire packets including the L2 CRC/FCS. If the card is not configured to discard the CRC/FCS, this can confuse applications that use libpcap if they're not prepared for packets to have an FCS. Libpcap now reads the environment variable ERF_FCS_BITS to determine how many bits of CRC/FCS to strip from the end of the captured frame. This defaults to 32 for use with Ethernet. If the card is configured to strip the CRC/FCS, then set ERF_FCS_BITS=0. If used with a HDLC/PoS/PPP/Frame Relay link with 16 bit CRC/FCS, then set ERF_FCS_BITS=16. If you wish to create a pcap file that DOES contain the Ethernet FCS, specify the environment variable ERF_DONT_STRIP_FCS. This will cause the existing FCS to be captured into the pcap file. Note some applications may incorrectly report capture errors or oversize packets when reading these files. ---------------------------------------------------------------------- Please submit bug reports via . Please also visit our Web site at: http://www.endace.com/ For more information about Endace DAG cards contact . libpcap-1.8.1/pcap_tstamp_type_val_to_name.3pcap0000644000026300017510000000364013003771737020141 0ustar mcrmcr.\" .\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_TSTAMP_TYPE_VAL_TO_NAME 3PCAP "12 December 2013" .SH NAME pcap_tstamp_type_val_to_name, pcap_tstamp_type_val_to_description \- get a name or description for a time stamp type value .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B const char *pcap_tstamp_type_val_to_name(int tstamp_type); const char *pcap_tstamp_type_val_to_description(int tstamp_type); .ft .fi .SH DESCRIPTION .B pcap_tstamp_type_val_to_name() translates a time stamp type value to the corresponding time stamp type name. .B NULL is returned on failure. .PP .B pcap_tstamp_type_val_to_description() translates a time stamp type value to a short description of that time stamp type. .B NULL is returned on failure. .SH SEE ALSO pcap(3PCAP), pcap_tstamp_type_name_to_val(3PCAP) libpcap-1.8.1/pcap_dump_file.3pcap0000644000026300017510000000304013003771737015162 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_DUMP_FILE 3PCAP "3 January 2014" .SH NAME pcap_dump_file \- get the standard I/O stream for a savefile being written .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B FILE *pcap_dump_file(pcap_dumper_t *p); .ft .fi .SH DESCRIPTION .B pcap_dump_file() returns the standard I/O stream of the ``savefile'' opened by .BR pcap_dump_open() . .SH SEE ALSO pcap(3PCAP) libpcap-1.8.1/pcap_lib_version.3pcap0000644000026300017510000000314513003771737015537 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_LIB_VERSION 3PCAP "3 January 2014" .SH NAME pcap_lib_version \- get the version information for libpcap .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B const char *pcap_lib_version(void); .ft .fi .SH DESCRIPTION .B pcap_lib_version() returns a pointer to a string giving information about the version of the libpcap library being used; note that it contains more information than just a version number. .SH SEE ALSO pcap(3PCAP) libpcap-1.8.1/pcap_tstamp_type_name_to_val.3pcap0000644000026300017510000000344613003771737020145 0ustar mcrmcr.\" .\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_TSTAMP_TYPE_NAME_TO_VAL 3PCAP "5 December 2014" .SH NAME pcap_tstamp_type_name_to_val \- get the time stamp type value corresponding to a time stamp type name .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_tstamp_type_name_to_val(const char *name); .ft .fi .SH DESCRIPTION .B pcap_tstamp_type_name_to_val() translates a time stamp type name to the corresponding time stamp type value. The translation is case-insensitive. .SH RETURN VALUE .B pcap_tstamp_type_name_to_val() returns time stamp type value on success and .B PCAP_ERROR on failure. .SH SEE ALSO pcap(3PCAP), pcap_tstamp_type_val_to_name(3PCAP) libpcap-1.8.1/config/0000755000026300017510000000000013003775545012534 5ustar mcrmcrlibpcap-1.8.1/config/have_siocglifconf.c0000644000026300017510000000017513003771737016352 0ustar mcrmcr#include #include #include int main() { ioctl(0, SIOCGLIFCONF, (char *)0); } libpcap-1.8.1/missing/0000755000026300017510000000000013003775545012740 5ustar mcrmcrlibpcap-1.8.1/missing/getopt.c0000644000026300017510000000771013003771737014412 0ustar mcrmcr/* * Copyright (c) 1987, 1993, 1994 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; #endif /* LIBC_SCCS and not lint */ #include #include #include #include "getopt.h" int opterr = 1, /* if error message should be printed */ optind = 1, /* index into parent argv vector */ optopt, /* character checked for validity */ optreset; /* reset getopt */ char *optarg; /* argument associated with option */ #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int getopt(nargc, nargv, ostr) int nargc; char * const *nargv; const char *ostr; { char *cp; static char *__progname; static char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ if (__progname == NULL) { if ((cp = strrchr(nargv[0], '/')) != NULL) __progname = cp + 1; else __progname = nargv[0]; } if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc || *(place = nargv[optind]) != '-') { place = EMSG; return (-1); } if (place[1] && *++place == '-') { /* found "--" */ ++optind; place = EMSG; return (-1); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { /* * if the user didn't specify '-' as an option, * assume it means -1. */ if (optopt == (int)'-') return (-1); if (!*place) ++optind; if (opterr && *ostr != ':') (void)fprintf(stderr, "%s: illegal option -- %c\n", __progname, optopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ optarg = place; else if (nargc <= ++optind) { /* no arg */ place = EMSG; if (*ostr == ':') return (BADARG); if (opterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", __progname, optopt); return (BADCH); } else /* white space */ optarg = nargv[optind]; place = EMSG; ++optind; } return (optopt); /* dump back option letter */ } libpcap-1.8.1/missing/getopt.h0000644000026300017510000000036213003771737014413 0ustar mcrmcr/* * Header for the getopt() we supply if the platform doesn't supply it. */ extern char *optarg; /* getopt(3) external variables */ extern int optind, opterr, optopt; extern int getopt(int nargc, char * const *nargv, const char *ostr); libpcap-1.8.1/missing/snprintf.c0000644000026300017510000003117413003771737014754 0ustar mcrmcr/* * Copyright (c) 1995-1999 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute 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 BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include enum format_flags { minus_flag = 1, plus_flag = 2, space_flag = 4, alternate_flag = 8, zero_flag = 16 }; /* * Common state */ struct state { unsigned char *str; unsigned char *s; unsigned char *theend; size_t sz; size_t max_sz; int (*append_char)(struct state *, unsigned char); int (*reserve)(struct state *, size_t); /* XXX - methods */ }; #ifndef HAVE_VSNPRINTF static int sn_reserve (struct state *state, size_t n) { return state->s + n > state->theend; } static int sn_append_char (struct state *state, unsigned char c) { if (sn_reserve (state, 1)) { return 1; } else { *state->s++ = c; return 0; } } #endif #if 0 static int as_reserve (struct state *state, size_t n) { if (state->s + n > state->theend) { int off = state->s - state->str; unsigned char *tmp; if (state->max_sz && state->sz >= state->max_sz) return 1; state->sz = max(state->sz * 2, state->sz + n); if (state->max_sz) state->sz = min(state->sz, state->max_sz); tmp = realloc (state->str, state->sz); if (tmp == NULL) return 1; state->str = tmp; state->s = state->str + off; state->theend = state->str + state->sz - 1; } return 0; } static int as_append_char (struct state *state, unsigned char c) { if(as_reserve (state, 1)) return 1; else { *state->s++ = c; return 0; } } #endif static int append_number(struct state *state, unsigned long num, unsigned base, char *rep, int width, int prec, int flags, int minusp) { int len = 0; int i; /* given precision, ignore zero flag */ if(prec != -1) flags &= ~zero_flag; else prec = 1; /* zero value with zero precision -> "" */ if(prec == 0 && num == 0) return 0; do{ if((*state->append_char)(state, rep[num % base])) return 1; len++; num /= base; }while(num); prec -= len; /* pad with prec zeros */ while(prec-- > 0){ if((*state->append_char)(state, '0')) return 1; len++; } /* add length of alternate prefix (added later) to len */ if(flags & alternate_flag && (base == 16 || base == 8)) len += base / 8; /* pad with zeros */ if(flags & zero_flag){ width -= len; if(minusp || (flags & space_flag) || (flags & plus_flag)) width--; while(width-- > 0){ if((*state->append_char)(state, '0')) return 1; len++; } } /* add alternate prefix */ if(flags & alternate_flag && (base == 16 || base == 8)){ if(base == 16) if((*state->append_char)(state, rep[10] + 23)) /* XXX */ return 1; if((*state->append_char)(state, '0')) return 1; } /* add sign */ if(minusp){ if((*state->append_char)(state, '-')) return 1; len++; } else if(flags & plus_flag) { if((*state->append_char)(state, '+')) return 1; len++; } else if(flags & space_flag) { if((*state->append_char)(state, ' ')) return 1; len++; } if(flags & minus_flag) /* swap before padding with spaces */ for(i = 0; i < len / 2; i++){ char c = state->s[-i-1]; state->s[-i-1] = state->s[-len+i]; state->s[-len+i] = c; } width -= len; while(width-- > 0){ if((*state->append_char)(state, ' ')) return 1; len++; } if(!(flags & minus_flag)) /* swap after padding with spaces */ for(i = 0; i < len / 2; i++){ char c = state->s[-i-1]; state->s[-i-1] = state->s[-len+i]; state->s[-len+i] = c; } return 0; } static int append_string (struct state *state, unsigned char *arg, int width, int prec, int flags) { if(prec != -1) width -= prec; else width -= strlen((char *)arg); if(!(flags & minus_flag)) while(width-- > 0) if((*state->append_char) (state, ' ')) return 1; if (prec != -1) { while (*arg && prec--) if ((*state->append_char) (state, *arg++)) return 1; } else { while (*arg) if ((*state->append_char) (state, *arg++)) return 1; } if(flags & minus_flag) while(width-- > 0) if((*state->append_char) (state, ' ')) return 1; return 0; } static int append_char(struct state *state, unsigned char arg, int width, int flags) { while(!(flags & minus_flag) && --width > 0) if((*state->append_char) (state, ' ')) return 1; if((*state->append_char) (state, arg)) return 1; while((flags & minus_flag) && --width > 0) if((*state->append_char) (state, ' ')) return 1; return 0; } /* * This can't be made into a function... */ #define PARSE_INT_FORMAT(res, arg, unsig) \ if (long_flag) \ res = (unsig long)va_arg(arg, unsig long); \ else if (short_flag) \ res = (unsig short)va_arg(arg, unsig int); \ else \ res = (unsig int)va_arg(arg, unsig int) /* * zyxprintf - return 0 or -1 */ static int xyzprintf (struct state *state, const char *char_format, va_list ap) { const unsigned char *format = (const unsigned char *)char_format; unsigned char c; while((c = *format++)) { if (c == '%') { int flags = 0; int width = 0; int prec = -1; int long_flag = 0; int short_flag = 0; /* flags */ while((c = *format++)){ if(c == '-') flags |= minus_flag; else if(c == '+') flags |= plus_flag; else if(c == ' ') flags |= space_flag; else if(c == '#') flags |= alternate_flag; else if(c == '0') flags |= zero_flag; else break; } if((flags & space_flag) && (flags & plus_flag)) flags ^= space_flag; if((flags & minus_flag) && (flags & zero_flag)) flags ^= zero_flag; /* width */ if (isdigit(c)) do { width = width * 10 + c - '0'; c = *format++; } while(isdigit(c)); else if(c == '*') { width = va_arg(ap, int); c = *format++; } /* precision */ if (c == '.') { prec = 0; c = *format++; if (isdigit(c)) do { prec = prec * 10 + c - '0'; c = *format++; } while(isdigit(c)); else if (c == '*') { prec = va_arg(ap, int); c = *format++; } } /* size */ if (c == 'h') { short_flag = 1; c = *format++; } else if (c == 'l') { long_flag = 1; c = *format++; } switch (c) { case 'c' : if(append_char(state, va_arg(ap, int), width, flags)) return -1; break; case 's' : if (append_string(state, va_arg(ap, unsigned char*), width, prec, flags)) return -1; break; case 'd' : case 'i' : { long arg; unsigned long num; int minusp = 0; PARSE_INT_FORMAT(arg, ap, signed); if (arg < 0) { minusp = 1; num = -arg; } else num = arg; if (append_number (state, num, 10, "0123456789", width, prec, flags, minusp)) return -1; break; } case 'u' : { unsigned long arg; PARSE_INT_FORMAT(arg, ap, unsigned); if (append_number (state, arg, 10, "0123456789", width, prec, flags, 0)) return -1; break; } case 'o' : { unsigned long arg; PARSE_INT_FORMAT(arg, ap, unsigned); if (append_number (state, arg, 010, "01234567", width, prec, flags, 0)) return -1; break; } case 'x' : { unsigned long arg; PARSE_INT_FORMAT(arg, ap, unsigned); if (append_number (state, arg, 0x10, "0123456789abcdef", width, prec, flags, 0)) return -1; break; } case 'X' :{ unsigned long arg; PARSE_INT_FORMAT(arg, ap, unsigned); if (append_number (state, arg, 0x10, "0123456789ABCDEF", width, prec, flags, 0)) return -1; break; } case 'p' : { unsigned long arg = (unsigned long)va_arg(ap, void*); if (append_number (state, arg, 0x10, "0123456789ABCDEF", width, prec, flags, 0)) return -1; break; } case 'n' : { int *arg = va_arg(ap, int*); *arg = state->s - state->str; break; } case '\0' : --format; /* FALLTHROUGH */ case '%' : if ((*state->append_char)(state, c)) return -1; break; default : if ( (*state->append_char)(state, '%') || (*state->append_char)(state, c)) return -1; break; } } else if ((*state->append_char) (state, c)) return -1; } return 0; } #ifndef HAVE_SNPRINTF int pcap_snprintf (char *str, size_t sz, const char *format, ...) { va_list args; int ret; va_start(args, format); ret = pcap_vsnprintf (str, sz, format, args); #ifdef PARANOIA { int ret2; char *tmp; tmp = malloc (sz); if (tmp == NULL) abort (); ret2 = pcap_vsprintf (tmp, format, args); if (ret != ret2 || strcmp(str, tmp)) abort (); free (tmp); } #endif va_end(args); return ret; } #endif #if 0 #ifndef HAVE_ASPRINTF int asprintf (char **ret, const char *format, ...) { va_list args; int val; va_start(args, format); val = vasprintf (ret, format, args); #ifdef PARANOIA { int ret2; char *tmp; tmp = malloc (val + 1); if (tmp == NULL) abort (); ret2 = vsprintf (tmp, format, args); if (val != ret2 || strcmp(*ret, tmp)) abort (); free (tmp); } #endif va_end(args); return val; } #endif #ifndef HAVE_ASNPRINTF int pcap_asnprintf (char **ret, size_t max_sz, const char *format, ...) { va_list args; int val; va_start(args, format); val = pcap_vasnprintf (ret, max_sz, format, args); #ifdef PARANOIA { int ret2; char *tmp; tmp = malloc (val + 1); if (tmp == NULL) abort (); ret2 = pcap_vsprintf (tmp, format, args); if (val != ret2 || strcmp(*ret, tmp)) abort (); free (tmp); } #endif va_end(args); return val; } #endif #ifndef HAVE_VASPRINTF int pcap_vasprintf (char **ret, const char *format, va_list args) { return pcap_vasnprintf (ret, 0, format, args); } #endif #ifndef HAVE_VASNPRINTF int pcap_vasnprintf (char **ret, size_t max_sz, const char *format, va_list args) { int st; size_t len; struct state state; state.max_sz = max_sz; state.sz = 1; state.str = malloc(state.sz); if (state.str == NULL) { *ret = NULL; return -1; } state.s = state.str; state.theend = state.s + state.sz - 1; state.append_char = as_append_char; state.reserve = as_reserve; st = xyzprintf (&state, format, args); if (st) { free (state.str); *ret = NULL; return -1; } else { char *tmp; *state.s = '\0'; len = state.s - state.str; tmp = realloc (state.str, len+1); if (tmp == NULL) { free (state.str); *ret = NULL; return -1; } *ret = tmp; return len; } } #endif #endif #ifndef HAVE_VSNPRINTF int pcap_vsnprintf (char *str, size_t sz, const char *format, va_list args) { struct state state; int ret; unsigned char *ustr = (unsigned char *)str; state.max_sz = 0; state.sz = sz; state.str = ustr; state.s = ustr; state.theend = ustr + sz - 1; state.append_char = sn_append_char; state.reserve = sn_reserve; ret = xyzprintf (&state, format, args); *state.s = '\0'; if (ret) return sz; else return state.s - state.str; } #endif libpcap-1.8.1/missing/strtok_r.c0000644000026300017510000000522513003771737014756 0ustar mcrmcr/*- * Copyright (c) 1998 Softweyr LLC. All rights reserved. * * strtok_r, from Berkeley strtok * Oct 13, 1998 by Wes Peters * * Copyright (c) 1988, 1993 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notices, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notices, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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 BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE * REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * From: @(#)strtok.c 8.1 (Berkeley) 6/4/93 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "portability.h" char * pcap_strtok_r(char *s, const char *delim, char **last) { char *spanp, *tok; int c, sc; if (s == NULL && (s = *last) == NULL) return (NULL); /* * Skip (span) leading delimiters (s += strspn(s, delim), sort of). */ cont: c = *s++; for (spanp = (char *)delim; (sc = *spanp++) != 0;) { if (c == sc) goto cont; } if (c == 0) { /* no non-delimiter characters */ *last = NULL; return (NULL); } tok = s - 1; /* * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). * Note that delim must have one NUL; we stop if we see that, too. */ for (;;) { c = *s++; spanp = (char *)delim; do { if ((sc = *spanp++) == c) { if (c == 0) s = NULL; else s[-1] = '\0'; *last = s; return (tok); } } while (sc != 0); } /* NOTREACHED */ } libpcap-1.8.1/missing/win_snprintf.c0000644000026300017510000000124013003771737015620 0ustar mcrmcr#include #include int pcap_vsnprintf(char *str, size_t str_size, const char *format, va_list args) { int ret; ret = _vsnprintf_s(str, str_size, _TRUNCATE, format, args); /* * XXX - _vsnprintf() and _snprintf() do *not* guarantee * that str is null-terminated, but C99's vsnprintf() * and snprintf() do, and we want to offer C99 behavior, * so forcibly null-terminate the string. */ str[str_size - 1] = '\0'; return (ret); } int pcap_snprintf(char *str, size_t str_size, const char *format, ...) { va_list args; int ret; va_start(args, format); ret = pcap_vsnprintf(str, str_size, format, args); va_end(args); return (ret); } libpcap-1.8.1/cmakeconfig.h.in0000644000026300017510000002302113003771737014310 0ustar mcrmcr/* cmakeconfig.h.in */ /* Enable optimizer debugging */ #cmakedefine BDEBUG 1 /* define if you have a cloning BPF device */ #cmakedefine HAVE_CLONING_BPF 1 /* define if you have the DAG API */ #cmakedefine HAVE_DAG_API 1 /* define if you have dag_get_erf_types() */ #cmakedefine HAVE_DAG_GET_ERF_TYPES 1 /* define if you have dag_get_stream_erf_types() */ #cmakedefine HAVE_DAG_GET_STREAM_ERF_TYPES 1 /* define if you have streams capable DAG API */ #cmakedefine HAVE_DAG_STREAMS_API 1 /* define if you have vdag_set_device_info() */ #cmakedefine HAVE_DAG_VDAG 1 /* Define to 1 if you have the declaration of `ether_hostton', and to 0 if you don't. */ #cmakedefine HAVE_DECL_ETHER_HOSTTON 1 /* define if you have a /dev/dlpi */ #cmakedefine HAVE_DEV_DLPI 1 /* if passive_req_t primitive exists */ #cmakedefine HAVE_DLPI_PASSIVE 1 /* Define to 1 if you have the `ether_hostton' function. */ #cmakedefine HAVE_ETHER_HOSTTON 1 /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ #cmakedefine HAVE_FSEEKO 1 /* on HP-UX 10.20 or later */ #cmakedefine HAVE_HPUX10_20_OR_LATER 1 /* on HP-UX 9.x */ #cmakedefine HAVE_HPUX9 1 /* if ppa_info_t_dl_module_id exists */ #cmakedefine HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_INTTYPES_H 1 /* if libdlpi exists */ #cmakedefine HAVE_LIBDLPI 1 /* if libnl exists */ #cmakedefine HAVE_LIBNL 1 /* if libnl exists and is version 2.x */ #cmakedefine HAVE_LIBNL_2_x 1 /* if libnl exists and is version 3.x */ #cmakedefine HAVE_LIBNL_3_x 1 /* libnl has NLE_FAILURE */ #cmakedefine HAVE_LIBNL_NLE 1 /* libnl has new-style socket api */ #cmakedefine HAVE_LIBNL_SOCKETS 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_COMPILER_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_ETHTOOL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_IF_BONDING_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_IF_PACKET_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_NET_TSTAMP_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_SOCKIOS_H 1 /* if tp_vlan_tci exists */ #cmakedefine HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_TYPES_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_USBDEVICE_FS_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_WIRELESS_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_MEMORY_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETINET_ETHER_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETINET_IF_ETHER_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETPACKET_IF_PACKET_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETPACKET_PACKET_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NET_IF_MEDIA_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NET_PFVAR_H 1 /* if there's an os_proto.h for this platform, to use additional prototypes */ #cmakedefine HAVE_OS_PROTO_H 1 /* Define to 1 if remote packet capture is to be supported */ #cmakedefine HAVE_REMOTE 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_PATHS_H 1 /* define if net/pfvar.h defines PF_NAT through PF_NORDR */ #cmakedefine HAVE_PF_NAT_THROUGH_PF_NORDR 1 /* define if you have the Septel API */ #cmakedefine HAVE_SEPTEL_API 1 /* define if you have the Myricom SNF API */ #cmakedefine HAVE_SNF_API 1 /* Define to 1 if you have the `snprintf' function. */ #cmakedefine HAVE_SNPRINTF 1 /* if struct sockaddr has the sa_len member */ #cmakedefine HAVE_SOCKADDR_SA_LEN 1 /* if struct sockaddr_storage exists */ #cmakedefine HAVE_SOCKADDR_STORAGE 1 /* define if socklen_t is defined */ #cmakedefine HAVE_SOCKLEN_T 1 /* On solaris */ #cmakedefine HAVE_SOLARIS 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDLIB_H 1 /* Define to 1 if you have the `strerror' function. */ #cmakedefine HAVE_STRERROR 1 /* Define to 1 if you have the `strlcpy' function. */ #cmakedefine HAVE_STRLCPY 1 /* Define to 1 if the system has the type `struct BPF_TIMEVAL'. */ #cmakedefine HAVE_STRUCT_BPF_TIMEVAL 1 /* Define to 1 if the system has the type `struct ether_addr'. */ #cmakedefine HAVE_STRUCT_ETHER_ADDR 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_BITYPES_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_BUFMOD_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_DLPI_EXT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_IOCCOM_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SOCKIO_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TYPES_H 1 /* define if you have the TurboCap API */ #cmakedefine HAVE_TC_API 1 /* if if_packet.h has tpacket_stats defined */ #cmakedefine HAVE_TPACKET_STATS 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H 1 /* if struct usbdevfs_ctrltransfer has bRequestType */ #cmakedefine HAVE_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE 1 /* Define to 1 if you have the `vsnprintf' function. */ #cmakedefine HAVE_VSNPRINTF 1 /* Define to 1 if you have the `PacketIsLoopbackAdapter' function. */ #cmakedefine HAVE_PACKET_IS_LOOPBACK_ADAPTER 1 /* define if the system supports zerocopy BPF */ #cmakedefine HAVE_ZEROCOPY_BPF 1 /* define if your compiler has __attribute__ */ #cmakedefine HAVE___ATTRIBUTE__ 1 /* IPv6 */ #cmakedefine INET6 1 /* if unaligned access fails */ #cmakedefine LBL_ALIGN 1 /* path for device for USB sniffing */ #cmakedefine LINUX_USB_MON_DEV 1 /* if we need a pcap_parse wrapper around yyparse */ #cmakedefine NEED_YYPARSE_WRAPPER 1 /* Define to 1 if netinet/ether.h declares `ether_hostton' */ #cmakedefine NETINET_ETHER_H_DECLARES_ETHER_HOSTTON 1 /* Define to 1 if netinet/if_ether.h declares `ether_hostton' */ #cmakedefine NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON 1 /* do not use protochain */ #cmakedefine NO_PROTOCHAIN 1 /* Define to the address where bug reports for this package should be sent. */ #cmakedefine PACKAGE_BUGREPORT 1 /* Define to the full name of this package. */ #cmakedefine PACKAGE_NAME 1 /* Define to the full name and version of this package. */ #cmakedefine PACKAGE_STRING 1 /* Define to the one symbol short name of this package. */ #cmakedefine PACKAGE_TARNAME 1 /* Define to the home page for this package. */ #cmakedefine PACKAGE_URL 1 /* Define to the version of this package. */ #cmakedefine PACKAGE_VERSION 1 /* /dev/dlpi directory */ #cmakedefine PCAP_DEV_PREFIX 1 /* target host supports Bluetooth sniffing */ #cmakedefine PCAP_SUPPORT_BT 1 /* target host supports Bluetooth Monitor */ #cmakedefine PCAP_SUPPORT_BT_MONITOR 1 /* support D-Bus sniffing */ #cmakedefine PCAP_SUPPORT_DBUS 1 /* target host supports netfilter sniffing */ #cmakedefine PCAP_SUPPORT_NETFILTER 1 /* use Linux packet ring capture if available */ #cmakedefine PCAP_SUPPORT_PACKET_RING 1 /* target host supports USB sniffing */ #cmakedefine PCAP_SUPPORT_USB 1 /* include ACN support */ #cmakedefine SITA 1 /* if struct sockaddr_hci has hci_channel member */ #cmakedefine SOCKADDR_HCI_HAS_HCI_CHANNEL 1 /* Define to 1 if you have the ANSI C header files. */ #cmakedefine STDC_HEADERS 1 /* Enable parser debugging */ #cmakedefine YYDEBUG 1 /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ #cmakedefine _FILE_OFFSET_BITS 1 /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ #cmakedefine _LARGEFILE_SOURCE 1 /* Define for large files, on AIX-style hosts. */ #cmakedefine _LARGE_FILES 1 /* define on AIX to get certain functions */ #cmakedefine _SUN 1 /* define if your compiler allows __attribute__((format)) without a warning */ #cmakedefine __ATTRIBUTE___FORMAT_OK 1 #if 0 /* to handle Ultrix compilers that don't support const in prototypes */ #cmakedefine const 1 /* Define as token for inline if inlining supported */ #cmakedefine inline 1 /* Define to `short' if int16_t not defined. */ #cmakedefine int16_t 1 /* Define to `int' if int32_t not defined. */ #cmakedefine int32_t 1 /* Define to `long long' if int64_t not defined. */ #cmakedefine int64_t 1 /* Define to `signed char' if int8_t not defined. */ #cmakedefine int8_t 1 /* on sinix */ #cmakedefine sinix 1 /* Define to `unsigned short' if u_int16_t not defined. */ #cmakedefine u_int16_t 1 /* Define to `unsigned int' if u_int32_t not defined. */ #cmakedefine u_int32_t 1 /* Define to `unsigned long long' if u_int64_t not defined. */ #cmakedefine u_int64_t 1 /* Define to `unsigned char' if u_int8_t not defined. */ #cmakedefine u_int8_t 1 #endif libpcap-1.8.1/pcap_setdirection.3pcap0000644000026300017510000000454613003771737015726 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_SETDIRECTION 3PCAP "8 March 2015" .SH NAME pcap_setdirection \- set the direction for which packets will be captured .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_setdirection(pcap_t *p, pcap_direction_t d); .ft .fi .SH DESCRIPTION .B pcap_setdirection() is used to specify a direction that packets will be captured. .I d is one of the constants .BR PCAP_D_IN , .B PCAP_D_OUT or .BR PCAP_D_INOUT . .B PCAP_D_IN will only capture packets received by the device, .B PCAP_D_OUT will only capture packets sent by the device and .B PCAP_D_INOUT will capture packets received by or sent by the device. .B PCAP_D_INOUT is the default setting if this function is not called. .PP .B pcap_setdirection() isn't necessarily fully supported on all platforms; some platforms might return an error for all values, and some other platforms might not support .BR PCAP_D_OUT . .PP This operation is not supported if a ``savefile'' is being read. .SH RETURN VALUE .B pcap_setdirection() returns 0 on success and \-1 on failure. If \-1 is returned, .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO pcap(3PCAP), pcap_geterr(3PCAP) libpcap-1.8.1/pcap_inject.3pcap0000644000026300017510000000650113003771737014477 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_INJECT 3PCAP "3 January 2014" .SH NAME pcap_inject, pcap_sendpacket \- transmit a packet .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_inject(pcap_t *p, const void *buf, size_t size); int pcap_sendpacket(pcap_t *p, const u_char *buf, int size); .ft .fi .SH DESCRIPTION .B pcap_inject() sends a raw packet through the network interface; .I buf points to the data of the packet, including the link-layer header, and .I size is the number of bytes in the packet. .PP Note that, even if you successfully open the network interface, you might not have permission to send packets on it, or it might not support sending packets; as .I pcap_open_live() doesn't have a flag to indicate whether to open for capturing, sending, or capturing and sending, you cannot request an open that supports sending and be notified at open time whether sending will be possible. Note also that some devices might not support sending packets. .PP Note that, on some platforms, the link-layer header of the packet that's sent might not be the same as the link-layer header of the packet supplied to .BR pcap_inject() , as the source link-layer address, if the header contains such an address, might be changed to be the address assigned to the interface on which the packet it sent, if the platform doesn't support sending completely raw and unchanged packets. Even worse, some drivers on some platforms might change the link-layer type field to whatever value libpcap used when attaching to the device, even on platforms that .I do nominally support sending completely raw and unchanged packets. .PP .B pcap_sendpacket() is like .BR pcap_inject() , but it returns 0 on success, rather than returning the number of bytes written. .RB ( pcap_inject() comes from OpenBSD; .B pcap_sendpacket() comes from WinPcap. Both are provided for compatibility.) .SH RETURN VALUE .B pcap_inject() returns the number of bytes written on success and \-1 on failure. .PP .B pcap_sendpacket() returns 0 on success and \-1 on failure. .PP If \-1 is returned, .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO pcap(3PCAP), pcap_geterr(3PCAP) libpcap-1.8.1/pcap-enet.c0000644000026300017510000001136713003771737013316 0ustar mcrmcr/* * Stanford Enetfilter subroutines for tcpdump * * Based on the MERIT NNstat etherifrt.c and the Ultrix pcap-pf.c * subroutines. * * Rayan Zachariassen, CA*Net */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "interface.h" struct packet_header { #ifdef IBMRTPC struct LengthWords length; struct tap_header tap; #endif /* IBMRTPC */ u_char packet[8] }; extern int errno; #define BUFSPACE (4*1024) /* Forwards */ static void efReadError(int, char *); void readloop(int cnt, int if_fd, struct bpf_program *fp, printfunc printit) { #ifdef IBMRTPC register struct packet_header *ph; register u_char *bp; register int inc; #else /* !IBMRTPC */ static struct timeval tv = { 0 }; #endif /* IBMRTPC */ register int cc, caplen; register struct bpf_insn *fcode = fp->bf_insns; union { struct packet_header hdr; u_char p[BUFSPACE]; u_short s; } buf; while (1) { if ((cc = read(if_fd, (char *)buf.p, sizeof(buf))) < 0) efReadError(if_fd, "reader"); #ifdef IBMRTPC /* * Loop through each packet. */ bp = buf.p; while (cc > 0) { ph = (struct packet_header *)bp; caplen = ph->tap.th_wirelen > snaplen ? snaplen : ph->tap .th_wirelen ; if (bpf_filter(fcode, (char *)ph->packet, ph->tap.th_wirelen, caplen)) { if (cnt >= 0 && --cnt < 0) goto out; (*printit)((char *)ph->packet, (struct timeval *)ph->tap.th_timestamp, ph->tap.th_wirelen, caplen); } inc = ph->length.PacketOffset; cc -= inc; bp += inc; } #else /* !IBMRTPC */ caplen = cc > snaplen ? snaplen : cc ; if (bpf_filter(fcode, buf.hdr.packet, cc, caplen)) { if (cnt >= 0 && --cnt < 0) goto out; (*printit)(buf.hdr.packet, &tv, cc, caplen); } #endif /* IBMRTPC */ } out: wrapup(if_fd); } /* Call ONLY if read() has returned an error on packet filter */ static void efReadError(int fid, char *msg) { if (errno == EINVAL) { /* read MAXINT bytes already! */ if (lseek(fid, 0, 0) < 0) { perror("tcpdump: efReadError/lseek"); exit(-1); } else return; } else { (void) fprintf(stderr, "tcpdump: "); perror(msg); exit(-1); } } void wrapup(int fd) { #ifdef IBMRTPC struct enstats es; if (ioctl(fd, EIOSTATS, &es) == -1) { perror("tcpdump: enet ioctl EIOSTATS error"); exit(-1); } fprintf(stderr, "%d packets queued", es.enStat_Rcnt); if (es.enStat_Rdrops > 0) fprintf(stderr, ", %d dropped", es.enStat_Rdrops); if (es.enStat_Reads > 0) fprintf(stderr, ", %d tcpdump %s", es.enStat_Reads, es.enStat_Reads > 1 ? "reads" : "read"); if (es.enStat_MaxRead > 1) fprintf(stderr, ", %d packets in largest read", es.enStat_MaxRead); putc('\n', stderr); #endif /* IBMRTPC */ close(fd); } int initdevice(char *device, int pflag, int *linktype) { struct eniocb ctl; struct enfilter filter; u_int maxwaiting; int if_fd; #ifdef IBMRTPC GETENETDEVICE(0, O_RDONLY, &if_fd); #else /* !IBMRTPC */ if_fd = open("/dev/enet", O_RDONLY, 0); #endif /* IBMRTPC */ if (if_fd == -1) { perror("tcpdump: enet open error"); error( "your system may not be properly configured; see \"man enet(4)\""); exit(-1); } /* Get operating parameters. */ if (ioctl(if_fd, EIOCGETP, (char *)&ctl) == -1) { perror("tcpdump: enet ioctl EIOCGETP error"); exit(-1); } /* Set operating parameters. */ #ifdef IBMRTPC ctl.en_rtout = 1 * ctl.en_hz; ctl.en_tr_etherhead = 1; ctl.en_tap_network = 1; ctl.en_multi_packet = 1; ctl.en_maxlen = BUFSPACE; #else /* !IBMRTPC */ ctl.en_rtout = 64; /* randomly picked value for HZ */ #endif /* IBMRTPC */ if (ioctl(if_fd, EIOCSETP, &ctl) == -1) { perror("tcpdump: enet ioctl EIOCSETP error"); exit(-1); } /* Flush the receive queue, since we've changed the operating parameters and we otherwise might receive data without headers. */ if (ioctl(if_fd, EIOCFLUSH) == -1) { perror("tcpdump: enet ioctl EIOCFLUSH error"); exit(-1); } /* Set the receive queue depth to its maximum. */ maxwaiting = ctl.en_maxwaiting; if (ioctl(if_fd, EIOCSETW, &maxwaiting) == -1) { perror("tcpdump: enet ioctl EIOCSETW error"); exit(-1); } #ifdef IBMRTPC /* Clear statistics. */ if (ioctl(if_fd, EIOCLRSTAT, 0) == -1) { perror("tcpdump: enet ioctl EIOCLRSTAT error"); exit(-1); } #endif /* IBMRTPC */ /* Set the filter (accept all packets). */ filter.enf_Priority = 3; filter.enf_FilterLen = 0; if (ioctl(if_fd, EIOCSETF, &filter) == -1) { perror("tcpdump: enet ioctl EIOCSETF error"); exit(-1); } /* * "enetfilter" supports only ethernets. */ *linktype = DLT_EN10MB; return(if_fd); } libpcap-1.8.1/tests/0000755000026300017510000000000013003775545012431 5ustar mcrmcrlibpcap-1.8.1/tests/opentest.c0000644000026300017510000001603613003771737014443 0ustar mcrmcr/* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 * 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. */ #ifndef lint static const char copyright[] _U_ = "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ The Regents of the University of California. All rights reserved.\n"; #endif #include #include #include #include #include #ifdef _WIN32 #include "getopt.h" #else #include #endif #include #define MAXIMUM_SNAPLEN 65535 static char *program_name; /* * This was introduced by Clang: * * http://clang.llvm.org/docs/LanguageExtensions.html#has-attribute * * in some version (which version?); it has been picked up by GCC 5.0. */ #ifndef __has_attribute /* * It's a macro, so you can check whether it's defined to check * whether it's supported. * * If it's not, define it to always return 0, so that we move on to * the fallback checks. */ #define __has_attribute(x) 0 #endif #if __has_attribute(noreturn) \ || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 205)) \ || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) \ || (defined(__xlC__) && __xlC__ >= 0x0A01) \ || (defined(__HP_aCC) && __HP_aCC >= 61000) /* * Compiler with support for it, or GCC 2.5 and later, or Solaris Studio 12 * (Sun C 5.9) and later, or IBM XL C 10.1 and later (do any earlier * versions of XL C support this?), or HP aCC A.06.10 and later. */ #define PCAP_NORETURN __attribute((noreturn)) #elif defined( _MSC_VER ) #define PCAP_NORETURN __declspec(noreturn) #else #define PCAP_NORETURN #endif #if __has_attribute(__format__) \ || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)) \ || (defined(__xlC__) && __xlC__ >= 0x0A01) \ || (defined(__HP_aCC) && __HP_aCC >= 61000) /* * Compiler with support for it, or GCC 2.3 and later, or IBM XL C 10.1 * and later (do any earlier versions of XL C support this?), * or HP aCC A.06.10 and later. */ #define PCAP_PRINTFLIKE(x,y) __attribute__((__format__(__printf__,x,y))) #else #define PCAP_PRINTFLIKE(x,y) #endif /* Forwards */ static void PCAP_NORETURN usage(void); static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); int main(int argc, char **argv) { register int op; register char *cp, *device; int dorfmon, dopromisc, snaplen, useactivate, bufsize; char ebuf[PCAP_ERRBUF_SIZE]; pcap_t *pd; int status = 0; device = NULL; dorfmon = 0; dopromisc = 0; snaplen = MAXIMUM_SNAPLEN; bufsize = 0; useactivate = 0; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; opterr = 0; while ((op = getopt(argc, argv, "i:Ips:aB:")) != -1) { switch (op) { case 'i': device = optarg; break; case 'I': dorfmon = 1; useactivate = 1; /* required for rfmon */ break; case 'p': dopromisc = 1; break; case 's': { char *end; snaplen = strtol(optarg, &end, 0); if (optarg == end || *end != '\0' || snaplen < 0 || snaplen > MAXIMUM_SNAPLEN) error("invalid snaplen %s", optarg); else if (snaplen == 0) snaplen = MAXIMUM_SNAPLEN; break; } case 'B': bufsize = atoi(optarg)*1024; if (bufsize <= 0) error("invalid packet buffer size %s", optarg); useactivate = 1; /* required for bufsize */ break; case 'a': useactivate = 1; break; default: usage(); /* NOTREACHED */ } } if (device == NULL) { device = pcap_lookupdev(ebuf); if (device == NULL) error("pcap_lookupdev failed: %s", ebuf); } if (useactivate) { pd = pcap_create(device, ebuf); if (pd == NULL) error("%s: pcap_create failed: %s", device, ebuf); status = pcap_set_snaplen(pd, snaplen); if (status != 0) error("%s: pcap_set_snaplen failed: %s", device, pcap_statustostr(status)); if (dopromisc) { status = pcap_set_promisc(pd, 1); if (status != 0) error("%s: pcap_set_promisc failed: %s", device, pcap_statustostr(status)); } if (dorfmon) { status = pcap_set_rfmon(pd, 1); if (status != 0) error("%s: pcap_set_rfmon failed: %s", device, pcap_statustostr(status)); } status = pcap_set_timeout(pd, 1000); if (status != 0) error("%s: pcap_set_timeout failed: %s", device, pcap_statustostr(status)); if (bufsize != 0) { status = pcap_set_buffer_size(pd, bufsize); if (status != 0) error("%s: pcap_set_buffer_size failed: %s", device, pcap_statustostr(status)); } status = pcap_activate(pd); if (status < 0) { /* * pcap_activate() failed. */ error("%s: %s\n(%s)", device, pcap_statustostr(status), pcap_geterr(pd)); } else if (status > 0) { /* * pcap_activate() succeeded, but it's warning us * of a problem it had. */ warning("%s: %s\n(%s)", device, pcap_statustostr(status), pcap_geterr(pd)); } else printf("%s opened successfully\n", device); } else { *ebuf = '\0'; pd = pcap_open_live(device, 65535, 0, 1000, ebuf); if (pd == NULL) error("%s", ebuf); else if (*ebuf) warning("%s", ebuf); else printf("%s opened successfully\n", device); } pcap_close(pd); exit(status < 0 ? 1 : 0); } static void usage(void) { (void)fprintf(stderr, "Usage: %s [ -Ipa ] [ -i interface ] [ -s snaplen ] [ -B bufsize ]\n", program_name); exit(1); } /* VARARGS */ static void error(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } exit(1); /* NOTREACHED */ } /* VARARGS */ static void warning(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: WARNING: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } } libpcap-1.8.1/tests/selpolltest.c0000644000026300017510000002367313003771737015161 0ustar mcrmcr/* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 * 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. */ #ifndef lint static const char copyright[] _U_ = "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* * Tests how select() and poll() behave on the selectable file descriptor * for a pcap_t. * * This would be significantly different on Windows, as it'd test * how WaitForMultipleObjects() would work on the event handle for a * pcap_t. */ #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_SELECT_H #include #else #include /* older UN*Xes */ #endif #include char *program_name; /* * This was introduced by Clang: * * http://clang.llvm.org/docs/LanguageExtensions.html#has-attribute * * in some version (which version?); it has been picked up by GCC 5.0. */ #ifndef __has_attribute /* * It's a macro, so you can check whether it's defined to check * whether it's supported. * * If it's not, define it to always return 0, so that we move on to * the fallback checks. */ #define __has_attribute(x) 0 #endif #if __has_attribute(noreturn) \ || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 205)) \ || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) \ || (defined(__xlC__) && __xlC__ >= 0x0A01) \ || (defined(__HP_aCC) && __HP_aCC >= 61000) /* * Compiler with support for it, or GCC 2.5 and later, or Solaris Studio 12 * (Sun C 5.9) and later, or IBM XL C 10.1 and later (do any earlier * versions of XL C support this?), or HP aCC A.06.10 and later. */ #define PCAP_NORETURN __attribute((noreturn)) #elif defined( _MSC_VER ) #define PCAP_NORETURN __declspec(noreturn) #else #define PCAP_NORETURN #endif #if __has_attribute(__format__) \ || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)) \ || (defined(__xlC__) && __xlC__ >= 0x0A01) \ || (defined(__HP_aCC) && __HP_aCC >= 61000) /* * Compiler with support for it, or GCC 2.3 and later, or IBM XL C 10.1 * and later (do any earlier versions of XL C support this?), * or HP aCC A.06.10 and later. */ #define PCAP_PRINTFLIKE(x,y) __attribute__((__format__(__printf__,x,y))) #else #define PCAP_PRINTFLIKE(x,y) #endif /* Forwards */ static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); static void PCAP_NORETURN usage(void); static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); static char *copy_argv(char **); static pcap_t *pd; int main(int argc, char **argv) { register int op; bpf_u_int32 localnet, netmask; register char *cp, *cmdbuf, *device; int doselect, dopoll, dotimeout, dononblock; struct bpf_program fcode; char ebuf[PCAP_ERRBUF_SIZE]; int selectable_fd; int status; int packet_count; device = NULL; doselect = 0; dopoll = 0; dotimeout = 0; dononblock = 0; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; opterr = 0; while ((op = getopt(argc, argv, "i:sptn")) != -1) { switch (op) { case 'i': device = optarg; break; case 's': doselect = 1; break; case 'p': dopoll = 1; break; case 't': dotimeout = 1; break; case 'n': dononblock = 1; break; default: usage(); /* NOTREACHED */ } } if (doselect && dopoll) { fprintf(stderr, "selpolltest: choose select (-s) or poll (-p), but not both\n"); return 1; } if (dotimeout && !doselect && !dopoll) { fprintf(stderr, "selpolltest: timeout (-t) requires select (-s) or poll (-p)\n"); return 1; } if (device == NULL) { device = pcap_lookupdev(ebuf); if (device == NULL) error("%s", ebuf); } *ebuf = '\0'; pd = pcap_open_live(device, 65535, 0, 1000, ebuf); if (pd == NULL) error("%s", ebuf); else if (*ebuf) warning("%s", ebuf); if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { localnet = 0; netmask = 0; warning("%s", ebuf); } cmdbuf = copy_argv(&argv[optind]); if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) error("%s", pcap_geterr(pd)); if (pcap_setfilter(pd, &fcode) < 0) error("%s", pcap_geterr(pd)); if (pcap_get_selectable_fd(pd) == -1) error("pcap_get_selectable_fd() fails"); if (dononblock) { if (pcap_setnonblock(pd, 1, ebuf) == -1) error("pcap_setnonblock failed: %s", ebuf); } selectable_fd = pcap_get_selectable_fd(pd); printf("Listening on %s\n", device); if (doselect) { for (;;) { fd_set setread, setexcept; struct timeval seltimeout; FD_ZERO(&setread); FD_SET(selectable_fd, &setread); FD_ZERO(&setexcept); FD_SET(selectable_fd, &setexcept); if (dotimeout) { seltimeout.tv_sec = 0; seltimeout.tv_usec = 1000; status = select(selectable_fd + 1, &setread, NULL, &setexcept, &seltimeout); } else { status = select(selectable_fd + 1, &setread, NULL, &setexcept, NULL); } if (status == -1) { printf("Select returns error (%s)\n", strerror(errno)); } else { if (status == 0) printf("Select timed out: "); else printf("Select returned a descriptor: "); if (FD_ISSET(selectable_fd, &setread)) printf("readable, "); else printf("not readable, "); if (FD_ISSET(selectable_fd, &setexcept)) printf("exceptional condition\n"); else printf("no exceptional condition\n"); packet_count = 0; status = pcap_dispatch(pd, -1, countme, (u_char *)&packet_count); if (status < 0) break; printf("%d packets seen, %d packets counted after select returns\n", status, packet_count); } } } else if (dopoll) { for (;;) { struct pollfd fd; int polltimeout; fd.fd = selectable_fd; fd.events = POLLIN; if (dotimeout) polltimeout = 1; else polltimeout = -1; status = poll(&fd, 1, polltimeout); if (status == -1) { printf("Poll returns error (%s)\n", strerror(errno)); } else { if (status == 0) printf("Poll timed out\n"); else { printf("Poll returned a descriptor: "); if (fd.revents & POLLIN) printf("readable, "); else printf("not readable, "); if (fd.revents & POLLERR) printf("exceptional condition, "); else printf("no exceptional condition, "); if (fd.revents & POLLHUP) printf("disconnect, "); else printf("no disconnect, "); if (fd.revents & POLLNVAL) printf("invalid\n"); else printf("not invalid\n"); } packet_count = 0; status = pcap_dispatch(pd, -1, countme, (u_char *)&packet_count); if (status < 0) break; printf("%d packets seen, %d packets counted after poll returns\n", status, packet_count); } } } else { for (;;) { packet_count = 0; status = pcap_dispatch(pd, -1, countme, (u_char *)&packet_count); if (status < 0) break; printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", status, packet_count); } } if (status == -2) { /* * We got interrupted, so perhaps we didn't * manage to finish a line we were printing. * Print an extra newline, just in case. */ putchar('\n'); } (void)fflush(stdout); if (status == -1) { /* * Error. Report it. */ (void)fprintf(stderr, "%s: pcap_loop: %s\n", program_name, pcap_geterr(pd)); } pcap_close(pd); exit(status == -1 ? 1 : 0); } static void countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) { int *counterp = (int *)user; (*counterp)++; } static void usage(void) { (void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n", program_name); exit(1); } /* VARARGS */ static void error(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } exit(1); /* NOTREACHED */ } /* VARARGS */ static void warning(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: WARNING: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } } /* * Copy arg vector into a new buffer, concatenating arguments with spaces. */ static char * copy_argv(register char **argv) { register char **p; register u_int len = 0; char *buf; char *src, *dst; p = argv; if (*p == 0) return 0; while (*p) len += strlen(*p++) + 1; buf = (char *)malloc(len); if (buf == NULL) error("copy_argv: malloc"); p = argv; dst = buf; while ((src = *p++) != NULL) { while ((*dst++ = *src++) != '\0') ; dst[-1] = ' '; } dst[-1] = '\0'; return buf; } libpcap-1.8.1/tests/reactivatetest.c0000644000026300017510000000510713003771737015626 0ustar mcrmcr/* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 * 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. */ #ifndef lint static const char copyright[] _U_ = "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ The Regents of the University of California. All rights reserved.\n"; #endif #include #include #include #include #include /* Forwards */ static void error(const char *, ...); int main(void) { char ebuf[PCAP_ERRBUF_SIZE]; pcap_t *pd; int status = 0; pd = pcap_open_live("lo0", 65535, 0, 1000, ebuf); if (pd == NULL) { pd = pcap_open_live("lo", 65535, 0, 1000, ebuf); if (pd == NULL) { error("Neither lo0 nor lo could be opened: %s", ebuf); return 2; } } status = pcap_activate(pd); if (status != PCAP_ERROR_ACTIVATED) { if (status == 0) error("pcap_activate() of opened pcap_t succeeded"); else if (status == PCAP_ERROR) error("pcap_activate() of opened pcap_t failed with %s, not PCAP_ERROR_ACTIVATED", pcap_geterr(pd)); else error("pcap_activate() of opened pcap_t failed with %s, not PCAP_ERROR_ACTIVATED", pcap_statustostr(status)); } return 0; } /* VARARGS */ static void error(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "reactivatetest: "); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } exit(1); /* NOTREACHED */ } libpcap-1.8.1/tests/findalldevstest.c0000644000026300017510000000766313003771737016003 0ustar mcrmcr#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #ifdef _WIN32 #include #else #include #include #include #include #endif #include static int ifprint(pcap_if_t *d); static char *iptos(bpf_u_int32 in); int main(int argc, char **argv) { pcap_if_t *alldevs; pcap_if_t *d; char *s; bpf_u_int32 net, mask; int exit_status = 0; char errbuf[PCAP_ERRBUF_SIZE+1]; if (pcap_findalldevs(&alldevs, errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); exit(1); } for(d=alldevs;d;d=d->next) { if (!ifprint(d)) exit_status = 2; } if ( (s = pcap_lookupdev(errbuf)) == NULL) { fprintf(stderr,"Error in pcap_lookupdev: %s\n",errbuf); exit_status = 2; } else { printf("Preferred device name: %s\n",s); } if (pcap_lookupnet(s, &net, &mask, errbuf) < 0) { fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf); exit_status = 2; } else { printf("Preferred device is on network: %s/%s\n",iptos(net), iptos(mask)); } exit(exit_status); } static int ifprint(pcap_if_t *d) { pcap_addr_t *a; #ifdef INET6 char ntop_buf[INET6_ADDRSTRLEN]; #endif const char *sep; int status = 1; /* success */ printf("%s\n",d->name); if (d->description) printf("\tDescription: %s\n",d->description); printf("\tFlags: "); sep = ""; if (d->flags & PCAP_IF_UP) { printf("%sUP", sep); sep = ", "; } if (d->flags & PCAP_IF_RUNNING) { printf("%sRUNNING", sep); sep = ", "; } if (d->flags & PCAP_IF_LOOPBACK) { printf("%sLOOPBACK", sep); sep = ", "; } printf("\n"); for(a=d->addresses;a;a=a->next) { if (a->addr != NULL) switch(a->addr->sa_family) { case AF_INET: printf("\tAddress Family: AF_INET\n"); if (a->addr) printf("\t\tAddress: %s\n", inet_ntoa(((struct sockaddr_in *)(a->addr))->sin_addr)); if (a->netmask) printf("\t\tNetmask: %s\n", inet_ntoa(((struct sockaddr_in *)(a->netmask))->sin_addr)); if (a->broadaddr) printf("\t\tBroadcast Address: %s\n", inet_ntoa(((struct sockaddr_in *)(a->broadaddr))->sin_addr)); if (a->dstaddr) printf("\t\tDestination Address: %s\n", inet_ntoa(((struct sockaddr_in *)(a->dstaddr))->sin_addr)); break; #ifdef INET6 case AF_INET6: printf("\tAddress Family: AF_INET6\n"); if (a->addr) printf("\t\tAddress: %s\n", inet_ntop(AF_INET6, ((struct sockaddr_in6 *)(a->addr))->sin6_addr.s6_addr, ntop_buf, sizeof ntop_buf)); if (a->netmask) printf("\t\tNetmask: %s\n", inet_ntop(AF_INET6, ((struct sockaddr_in6 *)(a->netmask))->sin6_addr.s6_addr, ntop_buf, sizeof ntop_buf)); if (a->broadaddr) printf("\t\tBroadcast Address: %s\n", inet_ntop(AF_INET6, ((struct sockaddr_in6 *)(a->broadaddr))->sin6_addr.s6_addr, ntop_buf, sizeof ntop_buf)); if (a->dstaddr) printf("\t\tDestination Address: %s\n", inet_ntop(AF_INET6, ((struct sockaddr_in6 *)(a->dstaddr))->sin6_addr.s6_addr, ntop_buf, sizeof ntop_buf)); break; #endif default: printf("\tAddress Family: Unknown (%d)\n", a->addr->sa_family); break; } else { fprintf(stderr, "\tWarning: a->addr is NULL, skipping this address.\n"); status = 0; } } printf("\n"); return status; } /* From tcptraceroute */ #define IPTOSBUFFERS 12 static char *iptos(bpf_u_int32 in) { static char output[IPTOSBUFFERS][3*4+3+1]; static short which; u_char *p; p = (u_char *)∈ which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1); sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); return output[which]; } libpcap-1.8.1/tests/can_set_rfmon_test.c0000644000026300017510000000515413003771737016455 0ustar mcrmcr/* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 * 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. */ #ifndef lint static const char copyright[] _U_ = "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ The Regents of the University of California. All rights reserved.\n"; #endif #include #include #include #include #include static const char *program_name; /* Forwards */ static void error(const char *, ...); int main(int argc, char **argv) { const char *cp; pcap_t *pd; char ebuf[PCAP_ERRBUF_SIZE]; int status; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; if (argc != 2) { fprintf(stderr, "Usage: %s \n", program_name); return 2; } pd = pcap_create(argv[1], ebuf); if (pd == NULL) error("%s", ebuf); status = pcap_can_set_rfmon(pd); if (status < 0) { if (status == PCAP_ERROR) error("%s: pcap_can_set_rfmon failed: %s", argv[1], pcap_geterr(pd)); else error("%s: pcap_can_set_rfmon failed: %s", argv[1], pcap_statustostr(status)); return 1; } printf("%s: Monitor mode %s be set\n", argv[1], status ? "can" : "cannot"); return 0; } /* VARARGS */ static void error(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } exit(1); /* NOTREACHED */ } libpcap-1.8.1/tests/valgrindtest.c0000644000026300017510000002737713003771737015322 0ustar mcrmcr/* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 * 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. */ /* * This doesn't actually test libpcap itself; it tests whether * valgrind properly handles the APIs libpcap uses. If it doesn't, * we end up getting patches submitted to "fix" references that * valgrind claims are being made to uninitialized data, when, in * fact, the OS isn't making any such references - or we get * valgrind *not* detecting *actual* incorrect references. * * Both BPF and Linux socket filters aren't handled correctly * by some versions of valgrind. See valgrind bug 318203 for * Linux: * * https://bugs.kde.org/show_bug.cgi?id=318203 * * and valgrind bug 312989 for OS X: * * https://bugs.kde.org/show_bug.cgi?id=312989 * * The fixes for both of those are checked into the official valgrind * repository. * * The unofficial FreeBSD port has similar issues to the official OS X * port, for similar reasons. */ #ifndef lint static const char copyright[] _U_ = "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ The Regents of the University of California. All rights reserved.\n"; #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) /* BSD-flavored OS - use BPF */ #define USE_BPF #elif defined(linux) /* Linux - use socket filters */ #define USE_SOCKET_FILTERS #else #error "Unknown platform or platform that doesn't support Valgrind" #endif #if defined(USE_BPF) #include #include /* * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the * native OS version, as we're going to be doing our own ioctls to * make sure that, in the uninitialized-data tests, the filters aren't * checked by libpcap before being handed to BPF. */ #define PCAP_DONT_INCLUDE_PCAP_BPF_H #elif defined(USE_SOCKET_FILTERS) #include #include #include #endif #include static char *program_name; /* * This was introduced by Clang: * * http://clang.llvm.org/docs/LanguageExtensions.html#has-attribute * * in some version (which version?); it has been picked up by GCC 5.0. */ #ifndef __has_attribute /* * It's a macro, so you can check whether it's defined to check * whether it's supported. * * If it's not, define it to always return 0, so that we move on to * the fallback checks. */ #define __has_attribute(x) 0 #endif #if __has_attribute(noreturn) \ || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 205)) \ || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) \ || (defined(__xlC__) && __xlC__ >= 0x0A01) \ || (defined(__HP_aCC) && __HP_aCC >= 61000) /* * Compiler with support for it, or GCC 2.5 and later, or Solaris Studio 12 * (Sun C 5.9) and later, or IBM XL C 10.1 and later (do any earlier * versions of XL C support this?), or HP aCC A.06.10 and later. */ #define PCAP_NORETURN __attribute((noreturn)) #elif defined( _MSC_VER ) #define PCAP_NORETURN __declspec(noreturn) #else #define PCAP_NORETURN #endif #if __has_attribute(__format__) \ || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)) \ || (defined(__xlC__) && __xlC__ >= 0x0A01) \ || (defined(__HP_aCC) && __HP_aCC >= 61000) /* * Compiler with support for it, or GCC 2.3 and later, or IBM XL C 10.1 * and later (do any earlier versions of XL C support this?), * or HP aCC A.06.10 and later. */ #define PCAP_PRINTFLIKE(x,y) __attribute__((__format__(__printf__,x,y))) #else #define PCAP_PRINTFLIKE(x,y) #endif /* Forwards */ static void PCAP_NORETURN usage(void); static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); /* * On Windows, we need to open the file in binary mode, so that * we get all the bytes specified by the size we get from "fstat()". * On UNIX, that's not necessary. O_BINARY is defined on Windows; * we define it as 0 if it's not defined, so it does nothing. */ #ifndef O_BINARY #define O_BINARY 0 #endif static char * read_infile(char *fname) { register int i, fd, cc; register char *cp; struct stat buf; fd = open(fname, O_RDONLY|O_BINARY); if (fd < 0) error("can't open %s: %s", fname, pcap_strerror(errno)); if (fstat(fd, &buf) < 0) error("can't stat %s: %s", fname, pcap_strerror(errno)); cp = malloc((u_int)buf.st_size + 1); if (cp == NULL) error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, fname, pcap_strerror(errno)); cc = read(fd, cp, (u_int)buf.st_size); if (cc < 0) error("read %s: %s", fname, pcap_strerror(errno)); if (cc != buf.st_size) error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); close(fd); /* replace "# comment" with spaces */ for (i = 0; i < cc; i++) { if (cp[i] == '#') while (i < cc && cp[i] != '\n') cp[i++] = ' '; } cp[cc] = '\0'; return (cp); } /* VARARGS */ static void error(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } exit(1); /* NOTREACHED */ } /* VARARGS */ static void warning(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: WARNING: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } } /* * Copy arg vector into a new buffer, concatenating arguments with spaces. */ static char * copy_argv(register char **argv) { register char **p; register u_int len = 0; char *buf; char *src, *dst; p = argv; if (*p == 0) return 0; while (*p) len += strlen(*p++) + 1; buf = (char *)malloc(len); if (buf == NULL) error("copy_argv: malloc"); p = argv; dst = buf; while ((src = *p++) != NULL) { while ((*dst++ = *src++) != '\0') ; dst[-1] = ' '; } dst[-1] = '\0'; return buf; } #define INSN_COUNT 17 int main(int argc, char **argv) { char *cp, *device; int op; int dorfmon, useactivate; char ebuf[PCAP_ERRBUF_SIZE]; char *infile; char *cmdbuf; pcap_t *pd; int status = 0; int pcap_fd; #if defined(USE_BPF) struct bpf_program bad_fcode; struct bpf_insn uninitialized[INSN_COUNT]; #elif defined(USE_SOCKET_FILTERS) struct sock_fprog bad_fcode; struct sock_filter uninitialized[INSN_COUNT]; #endif struct bpf_program fcode; device = NULL; dorfmon = 0; useactivate = 0; infile = NULL; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; opterr = 0; while ((op = getopt(argc, argv, "aF:i:I")) != -1) { switch (op) { case 'a': useactivate = 1; break; case 'F': infile = optarg; break; case 'i': device = optarg; break; case 'I': dorfmon = 1; useactivate = 1; /* required for rfmon */ break; default: usage(); /* NOTREACHED */ } } if (device == NULL) { /* * No interface specified; get whatever pcap_lookupdev() * finds. */ device = pcap_lookupdev(ebuf); if (device == NULL) { error("couldn't find interface to use: %s", ebuf); } } if (infile != NULL) { /* * Filter specified with "-F" and a file containing * a filter. */ cmdbuf = read_infile(infile); } else { if (optind < argc) { /* * Filter specified with arguments on the * command line. */ cmdbuf = copy_argv(&argv[optind+1]); } else { /* * No filter specified; use an empty string, which * compiles to an "accept all" filter. */ cmdbuf = ""; } } if (useactivate) { pd = pcap_create(device, ebuf); if (pd == NULL) error("%s: pcap_create() failed: %s", device, ebuf); status = pcap_set_snaplen(pd, 65535); if (status != 0) error("%s: pcap_set_snaplen failed: %s", device, pcap_statustostr(status)); status = pcap_set_promisc(pd, 1); if (status != 0) error("%s: pcap_set_promisc failed: %s", device, pcap_statustostr(status)); if (dorfmon) { status = pcap_set_rfmon(pd, 1); if (status != 0) error("%s: pcap_set_rfmon failed: %s", device, pcap_statustostr(status)); } status = pcap_set_timeout(pd, 1000); if (status != 0) error("%s: pcap_set_timeout failed: %s", device, pcap_statustostr(status)); status = pcap_activate(pd); if (status < 0) { /* * pcap_activate() failed. */ error("%s: %s\n(%s)", device, pcap_statustostr(status), pcap_geterr(pd)); } else if (status > 0) { /* * pcap_activate() succeeded, but it's warning us * of a problem it had. */ warning("%s: %s\n(%s)", device, pcap_statustostr(status), pcap_geterr(pd)); } } else { *ebuf = '\0'; pd = pcap_open_live(device, 65535, 1, 1000, ebuf); if (pd == NULL) error("%s", ebuf); else if (*ebuf) warning("%s", ebuf); } pcap_fd = pcap_fileno(pd); /* * Try setting a filter with an uninitialized bpf_program * structure. This should cause valgrind to report a * problem. * * We don't check for errors, because it could get an * error due to a bad pointer or count. */ #if defined(USE_BPF) ioctl(pcap_fd, BIOCSETF, &bad_fcode); #elif defined(USE_SOCKET_FILTERS) setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, sizeof(bad_fcode)); #endif /* * Try setting a filter with an initialized bpf_program * structure that points to an uninitialized program. * That should also cause valgrind to report a problem. * * We don't check for errors, because it could get an * error due to a bad pointer or count. */ #if defined(USE_BPF) bad_fcode.bf_len = INSN_COUNT; bad_fcode.bf_insns = uninitialized; ioctl(pcap_fd, BIOCSETF, &bad_fcode); #elif defined(USE_SOCKET_FILTERS) bad_fcode.len = INSN_COUNT; bad_fcode.filter = uninitialized; setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, sizeof(bad_fcode)); #endif /* * Now compile a filter and set the filter with that. * That should *not* cause valgrind to report a * problem. */ if (pcap_compile(pd, &fcode, cmdbuf, 1, 0) < 0) error("can't compile filter: %s", pcap_geterr(pd)); if (pcap_setfilter(pd, &fcode) < 0) error("can't set filter: %s", pcap_geterr(pd)); pcap_close(pd); exit(status < 0 ? 1 : 0); } static void usage(void) { (void)fprintf(stderr, "%s, with %s\n", program_name, pcap_lib_version()); (void)fprintf(stderr, "Usage: %s [-aI] [ -F file ] [ -I interface ] [ expression ]\n", program_name); exit(1); } libpcap-1.8.1/tests/filtertest.c0000644000026300017510000002046213003771737014765 0ustar mcrmcr/* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 * 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. */ #ifndef lint static const char copyright[] _U_ = "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ The Regents of the University of California. All rights reserved.\n"; #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #ifdef _WIN32 #include "getopt.h" #else #include #endif #include #include #ifdef _WIN32 #include typedef unsigned __int32 in_addr_t; #else #include #endif #include #include /* * This was introduced by Clang: * * http://clang.llvm.org/docs/LanguageExtensions.html#has-attribute * * in some version (which version?); it has been picked up by GCC 5.0. */ #ifndef __has_attribute /* * It's a macro, so you can check whether it's defined to check * whether it's supported. * * If it's not, define it to always return 0, so that we move on to * the fallback checks. */ #define __has_attribute(x) 0 #endif #if __has_attribute(noreturn) \ || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 205)) \ || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) \ || (defined(__xlC__) && __xlC__ >= 0x0A01) \ || (defined(__HP_aCC) && __HP_aCC >= 61000) /* * Compiler with support for it, or GCC 2.5 and later, or Solaris Studio 12 * (Sun C 5.9) and later, or IBM XL C 10.1 and later (do any earlier * versions of XL C support this?), or HP aCC A.06.10 and later. */ #define PCAP_NORETURN __attribute((noreturn)) #elif defined( _MSC_VER ) #define PCAP_NORETURN __declspec(noreturn) #else #define PCAP_NORETURN #endif #if __has_attribute(__format__) \ || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)) \ || (defined(__xlC__) && __xlC__ >= 0x0A01) \ || (defined(__HP_aCC) && __HP_aCC >= 61000) /* * Compiler with support for it, or GCC 2.3 and later, or IBM XL C 10.1 * and later (do any earlier versions of XL C support this?), * or HP aCC A.06.10 and later. */ #define PCAP_PRINTFLIKE(x,y) __attribute__((__format__(__printf__,x,y))) #else #define PCAP_PRINTFLIKE(x,y) #endif static char *program_name; /* Forwards */ static void PCAP_NORETURN usage(void); static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); static void warn(const char *, ...) PCAP_PRINTFLIKE(1, 2); #ifdef BDEBUG int dflag; #endif /* * On Windows, we need to open the file in binary mode, so that * we get all the bytes specified by the size we get from "fstat()". * On UNIX, that's not necessary. O_BINARY is defined on Windows; * we define it as 0 if it's not defined, so it does nothing. */ #ifndef O_BINARY #define O_BINARY 0 #endif static char * read_infile(char *fname) { register int i, fd, cc; register char *cp; struct stat buf; fd = open(fname, O_RDONLY|O_BINARY); if (fd < 0) error("can't open %s: %s", fname, pcap_strerror(errno)); if (fstat(fd, &buf) < 0) error("can't stat %s: %s", fname, pcap_strerror(errno)); cp = malloc((u_int)buf.st_size + 1); if (cp == NULL) error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, fname, pcap_strerror(errno)); cc = read(fd, cp, (u_int)buf.st_size); if (cc < 0) error("read %s: %s", fname, pcap_strerror(errno)); if (cc != buf.st_size) error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); close(fd); /* replace "# comment" with spaces */ for (i = 0; i < cc; i++) { if (cp[i] == '#') while (i < cc && cp[i] != '\n') cp[i++] = ' '; } cp[cc] = '\0'; return (cp); } /* VARARGS */ static void error(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } exit(1); /* NOTREACHED */ } /* VARARGS */ static void warn(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: WARNING: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } } /* * Copy arg vector into a new buffer, concatenating arguments with spaces. */ static char * copy_argv(register char **argv) { register char **p; register u_int len = 0; char *buf; char *src, *dst; p = argv; if (*p == 0) return 0; while (*p) len += strlen(*p++) + 1; buf = (char *)malloc(len); if (buf == NULL) error("copy_argv: malloc"); p = argv; dst = buf; while ((src = *p++) != NULL) { while ((*dst++ = *src++) != '\0') ; dst[-1] = ' '; } dst[-1] = '\0'; return buf; } int main(int argc, char **argv) { char *cp; int op; #ifndef BDEBUG int dflag; #endif char *infile; int Oflag; long snaplen; char *p; int dlt; bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN; char *cmdbuf; pcap_t *pd; struct bpf_program fcode; #ifdef _WIN32 if(wsockinit() != 0) return 1; #endif /* _WIN32 */ #ifndef BDEBUG dflag = 1; #else /* if optimizer debugging is enabled, output DOT graph * `dflag=4' is equivalent to -dddd to follow -d/-dd/-ddd * convention in tcpdump command line */ dflag = 4; #endif infile = NULL; Oflag = 1; snaplen = 68; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; opterr = 0; while ((op = getopt(argc, argv, "dF:m:Os:")) != -1) { switch (op) { case 'd': ++dflag; break; case 'F': infile = optarg; break; case 'O': Oflag = 0; break; case 'm': { in_addr_t addr; addr = inet_addr(optarg); if (addr == (in_addr_t)(-1)) error("invalid netmask %s", optarg); netmask = addr; break; } case 's': { char *end; snaplen = strtol(optarg, &end, 0); if (optarg == end || *end != '\0' || snaplen < 0 || snaplen > 65535) error("invalid snaplen %s", optarg); else if (snaplen == 0) snaplen = 65535; break; } default: usage(); /* NOTREACHED */ } } if (optind >= argc) { usage(); /* NOTREACHED */ } dlt = pcap_datalink_name_to_val(argv[optind]); if (dlt < 0) { dlt = (int)strtol(argv[optind], &p, 10); if (p == argv[optind] || *p != '\0') error("invalid data link type %s", argv[optind]); } if (infile) cmdbuf = read_infile(infile); else cmdbuf = copy_argv(&argv[optind+1]); pd = pcap_open_dead(dlt, snaplen); if (pd == NULL) error("Can't open fake pcap_t"); if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) error("%s", pcap_geterr(pd)); if (!bpf_validate(fcode.bf_insns, fcode.bf_len)) warn("Filter doesn't pass validation"); #ifdef BDEBUG // replace line feed with space for (cp = cmdbuf; *cp != '\0'; ++cp) { if (*cp == '\r' || *cp == '\n') { *cp = ' '; } } // only show machine code if BDEBUG defined, since dflag > 3 printf("machine codes for filter: %s\n", cmdbuf); #endif bpf_dump(&fcode, dflag); pcap_close(pd); exit(0); } static void usage(void) { (void)fprintf(stderr, "%s, with %s\n", program_name, pcap_lib_version()); (void)fprintf(stderr, "Usage: %s [-dO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n", program_name); exit(1); } libpcap-1.8.1/tests/capturetest.c0000644000026300017510000002012613003771737015140 0ustar mcrmcr/* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 * 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. */ #ifndef lint static const char copyright[] _U_ = "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ The Regents of the University of California. All rights reserved.\n"; #endif #include #include #include #include #include #ifdef _WIN32 #include "getopt.h" #else #include #endif #include #include #include static char *program_name; /* * This was introduced by Clang: * * http://clang.llvm.org/docs/LanguageExtensions.html#has-attribute * * in some version (which version?); it has been picked up by GCC 5.0. */ #ifndef __has_attribute /* * It's a macro, so you can check whether it's defined to check * whether it's supported. * * If it's not, define it to always return 0, so that we move on to * the fallback checks. */ #define __has_attribute(x) 0 #endif #if __has_attribute(noreturn) \ || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 205)) \ || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) \ || (defined(__xlC__) && __xlC__ >= 0x0A01) \ || (defined(__HP_aCC) && __HP_aCC >= 61000) /* * Compiler with support for it, or GCC 2.5 and later, or Solaris Studio 12 * (Sun C 5.9) and later, or IBM XL C 10.1 and later (do any earlier * versions of XL C support this?), or HP aCC A.06.10 and later. */ #define PCAP_NORETURN __attribute((noreturn)) #elif defined( _MSC_VER ) #define PCAP_NORETURN __declspec(noreturn) #else #define PCAP_NORETURN #endif #if __has_attribute(__format__) \ || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)) \ || (defined(__xlC__) && __xlC__ >= 0x0A01) \ || (defined(__HP_aCC) && __HP_aCC >= 61000) /* * Compiler with support for it, or GCC 2.3 and later, or IBM XL C 10.1 * and later (do any earlier versions of XL C support this?), * or HP aCC A.06.10 and later. */ #define PCAP_PRINTFLIKE(x,y) __attribute__((__format__(__printf__,x,y))) #else #define PCAP_PRINTFLIKE(x,y) #endif /* Forwards */ static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); static void PCAP_NORETURN usage(void); static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); static char *copy_argv(char **); static pcap_t *pd; int main(int argc, char **argv) { register int op; register char *cp, *cmdbuf, *device; long longarg; char *p; int timeout = 1000; int immediate = 0; int nonblock = 0; bpf_u_int32 localnet, netmask; struct bpf_program fcode; char ebuf[PCAP_ERRBUF_SIZE]; int status; int packet_count; device = NULL; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; opterr = 0; while ((op = getopt(argc, argv, "i:mnt:")) != -1) { switch (op) { case 'i': device = optarg; break; case 'm': immediate = 1; break; case 'n': nonblock = 1; break; case 't': longarg = strtol(optarg, &p, 10); if (p == optarg || *p != '\0') { error("Timeout value \"%s\" is not a number", optarg); /* NOTREACHED */ } if (longarg < 0) { error("Timeout value %ld is negative", longarg); /* NOTREACHED */ } if (longarg > INT_MAX) { error("Timeout value %ld is too large (> %d)", longarg, INT_MAX); /* NOTREACHED */ } timeout = (int)longarg; break; default: usage(); /* NOTREACHED */ } } if (device == NULL) { device = pcap_lookupdev(ebuf); if (device == NULL) error("%s", ebuf); } *ebuf = '\0'; pd = pcap_create(device, ebuf); if (pd == NULL) error("%s", ebuf); status = pcap_set_snaplen(pd, 65535); if (status != 0) error("%s: pcap_set_snaplen failed: %s", device, pcap_statustostr(status)); if (immediate) { status = pcap_set_immediate_mode(pd, 1); if (status != 0) error("%s: pcap_set_immediate_mode failed: %s", device, pcap_statustostr(status)); } status = pcap_set_timeout(pd, timeout); if (status != 0) error("%s: pcap_set_timeout failed: %s", device, pcap_statustostr(status)); status = pcap_activate(pd); if (status < 0) { /* * pcap_activate() failed. */ error("%s: %s\n(%s)", device, pcap_statustostr(status), pcap_geterr(pd)); } else if (status > 0) { /* * pcap_activate() succeeded, but it's warning us * of a problem it had. */ warning("%s: %s\n(%s)", device, pcap_statustostr(status), pcap_geterr(pd)); } if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { localnet = 0; netmask = 0; warning("%s", ebuf); } cmdbuf = copy_argv(&argv[optind]); if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) error("%s", pcap_geterr(pd)); if (pcap_setfilter(pd, &fcode) < 0) error("%s", pcap_geterr(pd)); if (pcap_setnonblock(pd, nonblock, ebuf) == -1) error("pcap_setnonblock failed: %s", ebuf); printf("Listening on %s\n", device); for (;;) { packet_count = 0; status = pcap_dispatch(pd, -1, countme, (u_char *)&packet_count); if (status < 0) break; if (status != 0) { printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", status, packet_count); } } if (status == -2) { /* * We got interrupted, so perhaps we didn't * manage to finish a line we were printing. * Print an extra newline, just in case. */ putchar('\n'); } (void)fflush(stdout); if (status == -1) { /* * Error. Report it. */ (void)fprintf(stderr, "%s: pcap_loop: %s\n", program_name, pcap_geterr(pd)); } pcap_close(pd); exit(status == -1 ? 1 : 0); } static void countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) { int *counterp = (int *)user; (*counterp)++; } static void usage(void) { (void)fprintf(stderr, "Usage: %s [ -mn ] [ -i interface ] [ -t timeout] [expression]\n", program_name); exit(1); } /* VARARGS */ static void error(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } exit(1); /* NOTREACHED */ } /* VARARGS */ static void warning(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: WARNING: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } } /* * Copy arg vector into a new buffer, concatenating arguments with spaces. */ static char * copy_argv(register char **argv) { register char **p; register u_int len = 0; char *buf; char *src, *dst; p = argv; if (*p == 0) return 0; while (*p) len += strlen(*p++) + 1; buf = (char *)malloc(len); if (buf == NULL) error("copy_argv: malloc"); p = argv; dst = buf; while ((src = *p++) != NULL) { while ((*dst++ = *src++) != '\0') ; dst[-1] = ' '; } dst[-1] = '\0'; return buf; } libpcap-1.8.1/tests/CMakeLists.txt0000644000026300017510000000263113003771737015172 0ustar mcrmcrcmake_minimum_required( VERSION 2.8.8 ) project( pcap_tests ) ###################################### # Register targets ###################################### if( MSVC ) file(GLOB PROJECT_SOURCE_LIST_WIN32_C ${pcap_SOURCE_DIR}/missing/getopt.c ) endif( MSVC ) ADD_EXECUTABLE (can_set_rfmon_test can_set_rfmon_test.c ${PROJECT_SOURCE_LIST_WIN32_C} ) target_link_libraries ( can_set_rfmon_test pcap ) ADD_EXECUTABLE (capturetest capturetest.c ${PROJECT_SOURCE_LIST_WIN32_C} ) target_link_libraries ( capturetest pcap ) ADD_EXECUTABLE (filtertest filtertest.c ${PROJECT_SOURCE_LIST_WIN32_C} ) target_link_libraries ( filtertest pcap ) ADD_EXECUTABLE (indalldevstest findalldevstest.c ${PROJECT_SOURCE_LIST_WIN32_C} ) target_link_libraries ( indalldevstest pcap ) ADD_EXECUTABLE (opentest opentest.c ${PROJECT_SOURCE_LIST_WIN32_C} ) target_link_libraries ( opentest pcap ) #ADD_EXECUTABLE (pcap_compile_test pcap_compile_test.c ${PROJECT_SOURCE_LIST_WIN32_C} ) #target_link_libraries ( pcap_compile_test pcap ) ADD_EXECUTABLE (reactivatetest reactivatetest.c ${PROJECT_SOURCE_LIST_WIN32_C} ) target_link_libraries ( reactivatetest pcap ) if( NOT WIN32 ) ADD_EXECUTABLE (selpolltest selpolltest.c ${PROJECT_SOURCE_LIST_WIN32_C} ) target_link_libraries ( selpolltest pcap ) endif() ADD_EXECUTABLE (valgrindtest valgrindtest.c ${PROJECT_SOURCE_LIST_WIN32_C} ) target_link_libraries ( valgrindtest pcap ) libpcap-1.8.1/pcap-config.10000644000026300017510000000442613003771737013544 0ustar mcrmcr.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" 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. .\" .TH PCAP-CONFIG 1 "15 February 2015" .SH NAME pcap-config \- write libpcap compiler and linker flags to standard output .SH SYNOPSIS .na .B pcap-config [ .B \-\-static ] [ .B \-\-cflags | \-\-libs | \-\-additional-libs ] .ad .SH DESCRIPTION .LP When run with the .B \-\-cflags option, .I pcap-config writes to the standard output the .B \-I compiler flags required to include libpcap's header files. When run with the .B \-\-libs option, .I pcap-config writes to the standard output the .B \-L and .B \-l linker flags required to link with libpcap, including .B \-l flags for libraries required by libpcap. When run with the .B \-\-additional-libs option, .I pcap-config writes to the standard output the .B \-L and .B \-l flags for libraries required by libpcap, but not the .B \-lpcap flag to link with libpcap itself. .LP By default, it writes flags appropriate for compiling with a dynamically-linked version of libpcap; the .B \-\-static flag causes it to write flags appropriate for compiling with a statically-linked version of libpcap. .SH "SEE ALSO" pcap(3PCAP) libpcap-1.8.1/nlpid.h0000644000026300017510000000324013003771737012544 0ustar mcrmcr/* * Copyright (c) 1996 * Juniper Networks, Inc. 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. The name of Juniper Networks may not * 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. */ /* Types missing from some systems */ /* * Network layer prototocol identifiers */ #ifndef ISO8473_CLNP #define ISO8473_CLNP 0x81 #endif #ifndef ISO9542_ESIS #define ISO9542_ESIS 0x82 #endif #ifndef ISO9542X25_ESIS #define ISO9542X25_ESIS 0x8a #endif #ifndef ISO10589_ISIS #define ISO10589_ISIS 0x83 #endif /* * this does not really belong in the nlpid.h file * however we need it for generating nice * IS-IS related BPF filters */ #define ISIS_L1_LAN_IIH 15 #define ISIS_L2_LAN_IIH 16 #define ISIS_PTP_IIH 17 #define ISIS_L1_LSP 18 #define ISIS_L2_LSP 20 #define ISIS_L1_CSNP 24 #define ISIS_L2_CSNP 25 #define ISIS_L1_PSNP 26 #define ISIS_L2_PSNP 27 #ifndef ISO8878A_CONS #define ISO8878A_CONS 0x84 #endif #ifndef ISO10747_IDRP #define ISO10747_IDRP 0x85 #endif libpcap-1.8.1/pcap-bt-monitor-linux.h0000644000026300017510000000322013003771737015604 0ustar mcrmcr/* * Copyright (c) 2014 Michal Labedzki for Tieto Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ int bt_monitor_findalldevs(pcap_if_t **alldevsp, char *err_str); pcap_t *bt_monitor_create(const char *device, char *ebuf, int *is_ours); libpcap-1.8.1/INSTALL.txt0000644000026300017510000004056313003771737013145 0ustar mcrmcrTo build libpcap, run "./configure" (a shell script). The configure script will determine your system attributes and generate an appropriate Makefile from Makefile.in. Next run "make". If everything goes well you can su to root and run "make install". However, you need not install libpcap if you just want to build tcpdump; just make sure the tcpdump and libpcap directory trees have the same parent directory. If configure says: configure: warning: cannot determine packet capture interface configure: warning: (see INSTALL for more info) then your system either does not support packet capture or your system does support packet capture but libpcap does not support that particular type. (If you have HP-UX, see below.) If your system uses a packet capture not supported by libpcap, please send us patches; don't forget to include an autoconf fragment suitable for use in configure.ac. It is possible to override the default packet capture type, although the circumstance where this works are limited. For example if you have installed bpf under SunOS 4 and wish to build a snit libpcap: ./configure --with-pcap=snit Another example is to force a supported packet capture type in the case where the configure scripts fails to detect it. You will need an ANSI C compiler to build libpcap. The configure script will abort if your compiler is not ANSI compliant. If this happens, use the generally available GNU C compiler (GCC). You will need either Flex 2.5.31 or later, or a version of Lex compatible with it (if any exist), to build libpcap. The configure script will abort if there isn't any such program. If you have an older version of Flex, or don't have a compatible version of Lex, the current version of flex is available at flex.sourceforge.net. You will need either Bison, Berkeley YACC, or a version of YACC compatible with them (if any exist), to build libpcap. The configure script will abort if there isn't any such program. If you don't have any such program, the current version of Bison can be found at http://ftp.gnu.org/gnu/bison/ and the current version of Berkeley YACC can be found at http://invisible-island.net/byacc/. Sometimes the stock C compiler does not interact well with Flex and Bison. The list of problems includes undefined references for alloca. You can get around this by installing GCC. If you use Solaris, there is a bug with bufmod(7) that is fixed in Solaris 2.3.2 (aka SunOS 5.3.2). Setting a snapshot length with the broken bufmod(7) results in data be truncated from the FRONT of the packet instead of the end. The work around is to not set a snapshot length but this results in performance problems since the entire packet is copied to user space. If you must run an older version of Solaris, there is a patch available from Sun; ask for bugid 1149065. After installing the patch, use "setenv BUFMOD_FIXED" to enable use of bufmod(7). However, we recommend you run a more current release of Solaris. If you use the SPARCompiler, you must be careful to not use the /usr/ucb/cc interface. If you do, you will get bogus warnings and perhaps errors. Either make sure your path has /opt/SUNWspro/bin before /usr/ucb or else: setenv CC /opt/SUNWspro/bin/cc before running configure. (You might have to do a "make distclean" if you already ran configure once). Also note that "make depend" won't work; while all of the known universe uses -M, the SPARCompiler uses -xM to generate makefile dependencies. If you are trying to do packet capture with a FORE ATM card, you may or may not be able to. They usually only release their driver in object code so unless their driver supports packet capture, there's not much libpcap can do. If you get an error like: tcpdump: recv_ack: bind error 0x??? when using DLPI, look for the DL_ERROR_ACK error return values, usually in /usr/include/sys/dlpi.h, and find the corresponding value. Under {DEC OSF/1, Digital UNIX, Tru64 UNIX}, packet capture must be enabled before it can be used. For instructions on how to enable packet filter support, see: ftp://ftp.digital.com/pub/Digital/dec-faq/Digital-UNIX Look for the "How do I configure the Berkeley Packet Filter and capture tcpdump traces?" item. Once you enable packet filter support, your OSF system will support bpf natively. Under Ultrix, packet capture must be enabled before it can be used. For instructions on how to enable packet filter support, see: ftp://ftp.digital.com/pub/Digital/dec-faq/ultrix If you use HP-UX, you must have at least version 9 and either the version of cc that supports ANSI C (cc -Aa) or else use the GNU C compiler. You must also buy the optional streams package. If you don't have: /usr/include/sys/dlpi.h /usr/include/sys/dlpi_ext.h then you don't have the streams package. In addition, we believe you need to install the "9.X LAN and DLPI drivers cumulative" patch (PHNE_6855) to make the version 9 DLPI work with libpcap. The DLPI streams package is standard starting with HP-UX 10. The HP implementation of DLPI is a little bit eccentric. Unlike Solaris, you must attach /dev/dlpi instead of the specific /dev/* network pseudo device entry in order to capture packets. The PPA is based on the ifnet "index" number. Under HP-UX 9, it is necessary to read /dev/kmem and the kernel symbol file (/hp-ux). Under HP-UX 10, DLPI can provide information for determining the PPA. It does not seem to be possible to trace the loopback interface. Unlike other DLPI implementations, PHYS implies MULTI and SAP and you get an error if you try to enable more than one promiscuous mode at a time. It is impossible to capture outbound packets on HP-UX 9. To do so on HP-UX 10, you will, apparently, need a late "LAN products cumulative patch" (at one point, it was claimed that this would be PHNE_18173 for s700/10.20; at another point, it was claimed that the required patches were PHNE_20892, PHNE_20725 and PHCO_10947, or newer patches), and to do so on HP-UX 11 you will, apparently, need the latest lancommon/DLPI patches and the latest driver patch for the interface(s) in use on HP-UX 11 (at one point, it was claimed that patches PHNE_19766, PHNE_19826, PHNE_20008, and PHNE_20735 did the trick). Furthermore, on HP-UX 10, you will need to turn on a kernel switch by doing echo 'lanc_outbound_promisc_flag/W 1' | adb -w /stand/vmunix /dev/mem You would have to arrange that this happen on reboots; the right way to do that would probably be to put it into an executable script file "/sbin/init.d/outbound_promisc" and making "/sbin/rc2.d/S350outbound_promisc" a symbolic link to that script. Finally, testing shows that there can't be more than one simultaneous DLPI user per network interface. If you use Linux, this version of libpcap is known to compile and run under Red Hat 4.0 with the 2.0.25 kernel. It may work with earlier 2.X versions but is guaranteed not to work with 1.X kernels. Running more than one libpcap program at a time, on a system with a 2.0.X kernel, can cause problems since promiscuous mode is implemented by twiddling the interface flags from the libpcap application; the packet capture mechanism in the 2.2 and later kernels doesn't have this problem. Also, packet timestamps aren't very good. This appears to be due to haphazard handling of the timestamp in the kernel. Note well: there is rumoured to be a version of tcpdump floating around called 3.0.3 that includes libpcap and is supposed to support Linux. You should be advised that neither the Network Research Group at LBNL nor the Tcpdump Group ever generated a release with this version number. The LBNL Network Research Group notes with interest that a standard cracker trick to get people to install trojans is to distribute bogus packages that have a version number higher than the current release. They also noted with annoyance that 90% of the Linux related bug reports they got are due to changes made to unofficial versions of their page. If you are having trouble but aren't using a version that came from tcpdump.org, please try that before submitting a bug report! On Linux, libpcap will not work if the kernel does not have the packet socket option enabled; see the README.linux file for information about this. If you use AIX, you may not be able to build libpcap from this release. We do not have an AIX system in house so it's impossible for us to test AIX patches submitted to us. We are told that you must link against /lib/pse.exp, that you must use AIX cc or a GNU C compiler newer than 2.7.2, and that you may need to run strload before running a libpcap application. Read the README.aix file for information on installing libpcap and configuring your system to be able to support libpcap. If you use NeXTSTEP, you will not be able to build libpcap from this release. If you use SINIX, you should be able to build libpcap from this release. It is known to compile and run on SINIX-Y/N 5.42 with the C-DS V1.0 or V1.1 compiler. But note that in some releases of SINIX, yacc emits incorrect code; if grammar.y fails to compile, change every occurence of: #ifdef YYDEBUG to: #if YYDEBUG Another workaround is to use flex and bison. If you use SCO, you might have trouble building libpcap from this release. We do not have a machine running SCO and have not had reports of anyone successfully building on it; the current release of libpcap does not compile on SCO OpenServer 5. Although SCO apparently supports DLPI to some extent, the DLPI in OpenServer 5 is very non-standard, and it appears that completely new code would need to be written to capture network traffic. SCO do not appear to provide tcpdump binaries for OpenServer 5 or OpenServer 6 as part of SCO Skunkware: http://www.sco.com/skunkware/ If you use UnixWare, you might be able to build libpcap from this release, or you might not. We do not have a machine running UnixWare, so we have not tested it; however, SCO provide packages for libpcap 0.6.2 and tcpdump 3.7.1 in the UnixWare 7/Open UNIX 8 part of SCO Skunkware, and the source package for libpcap 0.6.2 is not changed from the libpcap 0.6.2 source release, so this release of libpcap might also build without changes on UnixWare 7. If linking tcpdump fails with "Undefined: _alloca" when using bison on a Sun4, your version of Bison is broken. In any case version 1.16 or higher is recommended (1.14 is known to cause problems 1.16 is known to work). Either pick up a current version from: http://ftp.gnu.org/gnu/bison/ or hack around it by inserting the lines: #ifdef __GNUC__ #define alloca __builtin_alloca #else #ifdef sparc #include #else char *alloca (); #endif #endif right after the (100 line!) GNU license comment in bison.simple, remove grammar.[co] and fire up make again. If you use SunOS 4, your kernel must support streams NIT. If you run a libpcap program and it dies with: /dev/nit: No such device You must add streams NIT support to your kernel configuration, run config and boot the new kernel. If you are running a version of SunOS earlier than 4.1, you will need to replace the Sun supplied /sys/sun{3,4,4c}/OBJ/nit_if.o with the appropriate version from this distribution's SUNOS4 subdirectory and build a new kernel: nit_if.o.sun3-sunos4 (any flavor of sun3) nit_if.o.sun4c-sunos4.0.3c (SS1, SS1+, IPC, SLC, etc.) nit_if.o.sun4-sunos4 (Sun4's not covered by nit_if.o.sun4c-sunos4.0.3c) These nit replacements fix a bug that makes nit essentially unusable in pre-SunOS 4.1. In addition, our sun4c-sunos4.0.3c nit gives you timestamps to the resolution of the SS-1 clock (1 us) rather than the lousy 20ms timestamps Sun gives you (tcpdump will print out the full timestamp resolution if it finds it's running on a SS-1). FILES ----- CHANGES - description of differences between releases ChmodBPF/* - Mac OS X startup item to set ownership and permissions on /dev/bpf* CMakeLists.txt - CMake file CREDITS - people that have helped libpcap along INSTALL.txt - this file LICENSE - the license under which tcpdump is distributed Makefile.in - compilation rules (input to the configure script) README - description of distribution README.aix - notes on using libpcap on AIX README.dag - notes on using libpcap to capture on Endace DAG devices README.hpux - notes on using libpcap on HP-UX README.linux - notes on using libpcap on Linux README.macosx - notes on using libpcap on Mac OS X README.septel - notes on using libpcap to capture on Intel/Septel devices README.sita - notes on using libpcap to capture on SITA devices README.tru64 - notes on using libpcap on Digital/Tru64 UNIX README.Win32 - notes on using libpcap on Win32 systems (with WinPcap) SUNOS4 - pre-SunOS 4.1 replacement kernel nit modules VERSION - version of this release acconfig.h - support for post-2.13 autoconf aclocal.m4 - autoconf macros arcnet.h - ARCNET definitions atmuni31.h - ATM Q.2931 definitions bpf/net - copy of bpf_filter.c bpf_dump.c - BPF program printing routines bpf_filter.c - symlink to bpf/net/bpf_filter.c bpf_image.c - BPF disassembly routine config.guess - autoconf support config.h.in - autoconf input config.sub - autoconf support configure - configure script (run this first) configure.ac - configure script source dlpisubs.c - DLPI-related functions for pcap-dlpi.c and pcap-libdlpi.c dlpisubs.h - DLPI-related function declarations etherent.c - /etc/ethers support routines ethertype.h - Ethernet protocol types and names definitions fad-getad.c - pcap_findalldevs() for systems with getifaddrs() fad-gifc.c - pcap_findalldevs() for systems with only SIOCGIFLIST fad-glifc.c - pcap_findalldevs() for systems with SIOCGLIFCONF filtertest.c - test program for BPF compiler findalldevstest.c - test program for pcap_findalldevs() gencode.c - BPF code generation routines gencode.h - BPF code generation definitions grammar.y - filter string grammar ieee80211.h - 802.11 definitions inet.c - network routines install-sh - BSD style install script lbl/os-*.h - OS-dependent defines and prototypes llc.h - 802.2 LLC SAP definitions missing/* - replacements for missing library functions mkdep - construct Makefile dependency list msdos/* - drivers for MS-DOS capture support nametoaddr.c - hostname to address routines nlpid.h - OSI network layer protocol identifier definitions net - symlink to bpf/net optimize.c - BPF optimization routines pcap/bluetooth.h - public definition of DLT_BLUETOOTH_HCI_H4_WITH_PHDR header pcap/bpf.h - BPF definitions pcap/namedb.h - public libpcap name database definitions pcap/pcap.h - public libpcap definitions pcap/sll.h - public definition of DLT_LINUX_SLL header pcap/usb.h - public definition of DLT_USB header pcap-bpf.c - BSD Packet Filter support pcap-bpf.h - header for backwards compatibility pcap-bt-linux.c - Bluetooth capture support for Linux pcap-bt-linux.h - Bluetooth capture support for Linux pcap-dag.c - Endace DAG device capture support pcap-dag.h - Endace DAG device capture support pcap-dlpi.c - Data Link Provider Interface support pcap-dos.c - MS-DOS capture support pcap-dos.h - headers for MS-DOS capture support pcap-enet.c - enet support pcap-int.h - internal libpcap definitions pcap-libdlpi.c - Data Link Provider Interface support for systems with libdlpi pcap-linux.c - Linux packet socket support pcap-namedb.h - header for backwards compatibility pcap-nit.c - SunOS Network Interface Tap support pcap-nit.h - SunOS Network Interface Tap definitions pcap-null.c - dummy monitor support (allows offline use of libpcap) pcap-pf.c - Ultrix and Digital/Tru64 UNIX Packet Filter support pcap-pf.h - Ultrix and Digital/Tru64 UNIX Packet Filter definitions pcap-septel.c - Intel/Septel device capture support pcap-septel.h - Intel/Septel device capture support pcap-sita.c - SITA device capture support pcap-sita.h - SITA device capture support pcap-sita.html - SITA device capture documentation pcap-stdinc.h - includes and #defines for compiling on Win32 systems pcap-snit.c - SunOS 4.x STREAMS-based Network Interface Tap support pcap-snoop.c - IRIX Snoop network monitoring support pcap-usb-linux.c - USB capture support for Linux pcap-usb-linux.h - USB capture support for Linux pcap-win32.c - WinPcap capture support pcap.3pcap - manual entry for the library pcap.c - pcap utility routines pcap.h - header for backwards compatibility pcap_*.3pcap - manual entries for library functions pcap-filter.4 - manual entry for filter syntax pcap-linktype.4 - manual entry for link-layer header types ppp.h - Point to Point Protocol definitions savefile.c - offline support scanner.l - filter string scanner sunatmpos.h - definitions for SunATM capturing Win32 - headers and routines for building on Win32 systems libpcap-1.8.1/pcap-dag.h0000644000026300017510000000070513003771737013115 0ustar mcrmcr/* * pcap-dag.c: Packet capture interface for Endace DAG card. * * The functionality of this code attempts to mimic that of pcap-linux as much * as possible. This code is only needed when compiling in the DAG card code * at the same time as another type of device. * * Author: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com) */ pcap_t *dag_create(const char *, char *, int *); int dag_findalldevs(pcap_if_t **devlistp, char *errbuf); libpcap-1.8.1/pcap_set_datalink.3pcap0000644000026300017510000000352313003771737015666 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_SET_DATALINK 3PCAP "3 January 2014" .SH NAME pcap_set_datalink \- set the link-layer header type to be used by a capture device .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_set_datalink(pcap_t *p, int dlt); .ft .fi .SH DESCRIPTION .B pcap_set_datalink() is used to set the current link-layer header type of the pcap descriptor to the type specified by .IR dlt . .SH RETURN VALUE .B pcap_set_datalink() returns 0 on success and \-1 on failure. If \-1 is returned, .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO pcap(3PCAP), pcap_geterr(3PCAP), pcap_datalink_name_to_val(3PCAP) libpcap-1.8.1/config.h.in0000644000026300017510000002140513003771737013313 0ustar mcrmcr/* config.h.in. Generated from configure.ac by autoheader. */ /* Enable optimizer debugging */ #undef BDEBUG /* define if you have a cloning BPF device */ #undef HAVE_CLONING_BPF /* define if you have the DAG API */ #undef HAVE_DAG_API /* define if you have dag_get_erf_types() */ #undef HAVE_DAG_GET_ERF_TYPES /* define if you have dag_get_stream_erf_types() */ #undef HAVE_DAG_GET_STREAM_ERF_TYPES /* define if you have streams capable DAG API */ #undef HAVE_DAG_STREAMS_API /* define if you have vdag_set_device_info() */ #undef HAVE_DAG_VDAG /* Define to 1 if you have the declaration of `ether_hostton', and to 0 if you don't. */ #undef HAVE_DECL_ETHER_HOSTTON /* define if you have a /dev/dlpi */ #undef HAVE_DEV_DLPI /* if passive_req_t primitive exists */ #undef HAVE_DLPI_PASSIVE /* Define to 1 if you have the `ether_hostton' function. */ #undef HAVE_ETHER_HOSTTON /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ #undef HAVE_FSEEKO /* on HP-UX 10.20 or later */ #undef HAVE_HPUX10_20_OR_LATER /* on HP-UX 9.x */ #undef HAVE_HPUX9 /* if ppa_info_t_dl_module_id exists */ #undef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* if libdlpi exists */ #undef HAVE_LIBDLPI /* if libnl exists */ #undef HAVE_LIBNL /* if libnl exists and is version 2.x */ #undef HAVE_LIBNL_2_x /* if libnl exists and is version 3.x */ #undef HAVE_LIBNL_3_x /* libnl has NLE_FAILURE */ #undef HAVE_LIBNL_NLE /* libnl has new-style socket api */ #undef HAVE_LIBNL_SOCKETS /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_COMPILER_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_ETHTOOL_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_IF_BONDING_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_IF_PACKET_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_NET_TSTAMP_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_SOCKIOS_H /* if tp_vlan_tci exists */ #undef HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_USBDEVICE_FS_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_WIRELESS_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_ETHER_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IF_ETHER_H /* Define to 1 if you have the header file. */ #undef HAVE_NETPACKET_IF_PACKET_H /* Define to 1 if you have the header file. */ #undef HAVE_NETPACKET_PACKET_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF_MEDIA_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_PFVAR_H /* if there's an os_proto.h for this platform, to use additional prototypes */ #undef HAVE_OS_PROTO_H /* define if net/pfvar.h defines PF_NAT through PF_NORDR */ #undef HAVE_PF_NAT_THROUGH_PF_NORDR /* define if you have the Septel API */ #undef HAVE_SEPTEL_API /* define if you have the Myricom SNF API */ #undef HAVE_SNF_API /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF /* if struct sockaddr has the sa_len member */ #undef HAVE_SOCKADDR_SA_LEN /* if struct sockaddr_storage exists */ #undef HAVE_SOCKADDR_STORAGE /* define if socklen_t is defined */ #undef HAVE_SOCKLEN_T /* On solaris */ #undef HAVE_SOLARIS /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `strtok_r' function. */ #undef HAVE_STRTOK_R /* Define to 1 if the system has the type `struct BPF_TIMEVAL'. */ #undef HAVE_STRUCT_BPF_TIMEVAL /* Define to 1 if the system has the type `struct ether_addr'. */ #undef HAVE_STRUCT_ETHER_ADDR /* Define to 1 if you have the header file. */ #undef HAVE_SYS_BITYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_BUFMOD_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_DLPI_EXT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCCOM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKIO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* define if you have the TurboCap API */ #undef HAVE_TC_API /* if if_packet.h has tpacket_stats defined */ #undef HAVE_TPACKET_STATS /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* if struct usbdevfs_ctrltransfer has bRequestType */ #undef HAVE_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF /* define if the system supports zerocopy BPF */ #undef HAVE_ZEROCOPY_BPF /* define if your compiler has __attribute__ */ #undef HAVE___ATTRIBUTE__ /* IPv6 */ #undef INET6 /* if unaligned access fails */ #undef LBL_ALIGN /* path for device for USB sniffing */ #undef LINUX_USB_MON_DEV /* Define to 1 if netinet/ether.h declares `ether_hostton' */ #undef NETINET_ETHER_H_DECLARES_ETHER_HOSTTON /* Define to 1 if netinet/if_ether.h declares `ether_hostton' */ #undef NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON /* do not use protochain */ #undef NO_PROTOCHAIN /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* /dev/dlpi directory */ #undef PCAP_DEV_PREFIX /* target host supports Bluetooth sniffing */ #undef PCAP_SUPPORT_BT /* target host supports Bluetooth Monitor */ #undef PCAP_SUPPORT_BT_MONITOR /* support D-Bus sniffing */ #undef PCAP_SUPPORT_DBUS /* target host supports netfilter sniffing */ #undef PCAP_SUPPORT_NETFILTER /* use Linux packet ring capture if available */ #undef PCAP_SUPPORT_PACKET_RING /* target host supports USB sniffing */ #undef PCAP_SUPPORT_USB /* include ACN support */ #undef SITA /* if struct sockaddr_hci has hci_channel member */ #undef SOCKADDR_HCI_HAS_HCI_CHANNEL /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Enable parser debugging */ #undef YYDEBUG /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #undef YYTEXT_POINTER /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ #undef _LARGEFILE_SOURCE /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* define on AIX to get certain functions */ #undef _SUN /* define if your compiler allows __attribute__((format)) without a warning */ #undef __ATTRIBUTE___FORMAT_OK /* to handle Ultrix compilers that don't support const in prototypes */ #undef const /* Define as token for inline if inlining supported */ #undef inline /* Define to `short' if int16_t not defined. */ #undef int16_t /* Define to `int' if int32_t not defined. */ #undef int32_t /* Define to `long long' if int64_t not defined. */ #undef int64_t /* Define to `signed char' if int8_t not defined. */ #undef int8_t /* on sinix */ #undef sinix /* Define to `unsigned short' if u_int16_t not defined. */ #undef u_int16_t /* Define to `unsigned int' if u_int32_t not defined. */ #undef u_int32_t /* Define to `unsigned long long' if u_int64_t not defined. */ #undef u_int64_t /* Define to `unsigned char' if u_int8_t not defined. */ #undef u_int8_t libpcap-1.8.1/pcap-tc.h0000644000026300017510000000363113003771737012771 0ustar mcrmcr/* * Copyright (c) 2008 CACE Technologies, Davis (California) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of CACE Technologies 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __PCAP_TC_H__ #define __PCAP_TC_H__ /* * needed because gcc headers do not have C_ASSERT */ #ifndef C_ASSERT #define C_ASSERT(a) #endif #include /* * functions used effectively by the pcap library */ pcap_t * TcCreate(const char *device, char *ebuf, int *is_ours); int TcFindAllDevs(pcap_if_t **alldevsp, char *errbuf); #endif libpcap-1.8.1/pcap_stats.3pcap0000644000026300017510000000654313003771737014367 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_STATS 3PCAP "3 January 2014" .SH NAME pcap_stats \- get capture statistics .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_stats(pcap_t *p, struct pcap_stat *ps); .ft .fi .SH DESCRIPTION .B pcap_stats() fills in the .B struct pcap_stat pointed to by its second argument. The values represent packet statistics from the start of the run to the time of the call. .PP .B pcap_stats() is supported only on live captures, not on ``savefiles''; no statistics are stored in ``savefiles'', so no statistics are available when reading from a ``savefile''. .PP A .B struct pcap_stat has the following members: .RS .TP .B ps_recv number of packets received; .TP .B ps_drop number of packets dropped because there was no room in the operating system's buffer when they arrived, because packets weren't being read fast enough; .TP .B ps_ifdrop number of packets dropped by the network interface or its driver. .RE .PP The statistics do not behave the same way on all platforms. .B ps_recv might count packets whether they passed any filter set with .BR pcap_setfilter (3PCAP) or not, or it might count only packets that pass the filter. It also might, or might not, count packets dropped because there was no room in the operating system's buffer when they arrived. .B ps_drop is not available on all platforms; it is zero on platforms where it's not available. If packet filtering is done in libpcap, rather than in the operating system, it would count packets that don't pass the filter. Both .B ps_recv and .B ps_drop might, or might not, count packets not yet read from the operating system and thus not yet seen by the application. .B ps_ifdrop might, or might not, be implemented; if it's zero, that might mean that no packets were dropped by the interface, or it might mean that the statistic is unavailable, so it should not be treated as an indication that the interface did not drop any packets. .SH RETURN VALUE .B pcap_stats() returns 0 on success and returns \-1 if there is an error or if .I p doesn't support packet statistics. If \-1 is returned, .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO pcap(3PCAP), pcap_geterr(3PCAP) libpcap-1.8.1/bpf_dump.c0000644000026300017510000000361313003771737013231 0ustar mcrmcr/* * Copyright (c) 1992, 1993, 1994, 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include void bpf_dump(const struct bpf_program *p, int option) { const struct bpf_insn *insn; int i; int n = p->bf_len; insn = p->bf_insns; if (option > 2) { printf("%d\n", n); for (i = 0; i < n; ++insn, ++i) { printf("%u %u %u %u\n", insn->code, insn->jt, insn->jf, insn->k); } return ; } if (option > 1) { for (i = 0; i < n; ++insn, ++i) printf("{ 0x%x, %d, %d, 0x%08x },\n", insn->code, insn->jt, insn->jf, insn->k); return; } for (i = 0; i < n; ++insn, ++i) { #ifdef BDEBUG extern int bids[]; if (bids[i] > 0) printf("[%02d]", bids[i] - 1); else printf(" -- "); #endif puts(bpf_image(insn, i)); } } libpcap-1.8.1/bpf/0000755000026300017510000000000013003775545012036 5ustar mcrmcrlibpcap-1.8.1/bpf/net/0000755000026300017510000000000013003775545012624 5ustar mcrmcrlibpcap-1.8.1/bpf/net/bpf_filter.c0000644000026300017510000004060213003771737015105 0ustar mcrmcr/*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)bpf.c 7.5 (Berkeley) 7/15/91 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef _WIN32 #include #else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_BITYPES_H #include #endif #include #include #include #define SOLARIS (defined(sun) && (defined(__SVR4) || defined(__svr4__))) #if defined(__hpux) || SOLARIS # include # include # define mbuf msgb # define m_next b_cont # define MLEN(m) ((m)->b_wptr - (m)->b_rptr) # define mtod(m,t) ((t)(m)->b_rptr) #else /* defined(__hpux) || SOLARIS */ # define MLEN(m) ((m)->m_len) #endif /* defined(__hpux) || SOLARIS */ #endif /* _WIN32 */ #include #if !defined(KERNEL) && !defined(_KERNEL) #include #endif #define int32 bpf_int32 #define u_int32 bpf_u_int32 #ifndef LBL_ALIGN /* * XXX - IA-64? If not, this probably won't work on Win64 IA-64 * systems, unless LBL_ALIGN is defined elsewhere for them. * XXX - SuperH? If not, this probably won't work on WinCE SuperH * systems, unless LBL_ALIGN is defined elsewhere for them. */ #if defined(sparc) || defined(__sparc__) || defined(mips) || \ defined(ibm032) || defined(__alpha) || defined(__hpux) || \ defined(__arm__) #define LBL_ALIGN #endif #endif #ifndef LBL_ALIGN #ifndef _WIN32 #include #endif #define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p)) #define EXTRACT_LONG(p) (ntohl(*(u_int32 *)p)) #else #define EXTRACT_SHORT(p)\ ((u_short)\ ((u_short)*((u_char *)p+0)<<8|\ (u_short)*((u_char *)p+1)<<0)) #define EXTRACT_LONG(p)\ ((u_int32)*((u_char *)p+0)<<24|\ (u_int32)*((u_char *)p+1)<<16|\ (u_int32)*((u_char *)p+2)<<8|\ (u_int32)*((u_char *)p+3)<<0) #endif #if defined(KERNEL) || defined(_KERNEL) # if !defined(__hpux) && !SOLARIS #include # endif #define MINDEX(len, _m, _k) \ { \ len = MLEN(m); \ while ((_k) >= len) { \ (_k) -= len; \ (_m) = (_m)->m_next; \ if ((_m) == 0) \ return 0; \ len = MLEN(m); \ } \ } static int m_xword(m, k, err) register struct mbuf *m; register int k, *err; { register int len; register u_char *cp, *np; register struct mbuf *m0; MINDEX(len, m, k); cp = mtod(m, u_char *) + k; if (len - k >= 4) { *err = 0; return EXTRACT_LONG(cp); } m0 = m->m_next; if (m0 == 0 || MLEN(m0) + len - k < 4) goto bad; *err = 0; np = mtod(m0, u_char *); switch (len - k) { case 1: return (cp[0] << 24) | (np[0] << 16) | (np[1] << 8) | np[2]; case 2: return (cp[0] << 24) | (cp[1] << 16) | (np[0] << 8) | np[1]; default: return (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | np[0]; } bad: *err = 1; return 0; } static int m_xhalf(m, k, err) register struct mbuf *m; register int k, *err; { register int len; register u_char *cp; register struct mbuf *m0; MINDEX(len, m, k); cp = mtod(m, u_char *) + k; if (len - k >= 2) { *err = 0; return EXTRACT_SHORT(cp); } m0 = m->m_next; if (m0 == 0) goto bad; *err = 0; return (cp[0] << 8) | mtod(m0, u_char *)[0]; bad: *err = 1; return 0; } #endif #ifdef __linux__ #include #include #include #endif enum { BPF_S_ANC_NONE, BPF_S_ANC_VLAN_TAG, BPF_S_ANC_VLAN_TAG_PRESENT, }; /* * Execute the filter program starting at pc on the packet p * wirelen is the length of the original packet * buflen is the amount of data present * aux_data is auxiliary data, currently used only when interpreting * filters intended for the Linux kernel in cases where the kernel * rejects the filter; it contains VLAN tag information * For the kernel, p is assumed to be a pointer to an mbuf if buflen is 0, * in all other cases, p is a pointer to a buffer and buflen is its size. * * Thanks to Ani Sinha for providing initial implementation */ u_int bpf_filter_with_aux_data(pc, p, wirelen, buflen, aux_data) register const struct bpf_insn *pc; register const u_char *p; u_int wirelen; register u_int buflen; register const struct bpf_aux_data *aux_data; { register u_int32 A, X; register bpf_u_int32 k; u_int32 mem[BPF_MEMWORDS]; #if defined(KERNEL) || defined(_KERNEL) struct mbuf *m, *n; int merr, len; if (buflen == 0) { m = (struct mbuf *)p; p = mtod(m, u_char *); buflen = MLEN(m); } else m = NULL; #endif if (pc == 0) /* * No filter means accept all. */ return (u_int)-1; A = 0; X = 0; --pc; while (1) { ++pc; switch (pc->code) { default: #if defined(KERNEL) || defined(_KERNEL) return 0; #else abort(); #endif case BPF_RET|BPF_K: return (u_int)pc->k; case BPF_RET|BPF_A: return (u_int)A; case BPF_LD|BPF_W|BPF_ABS: k = pc->k; if (k > buflen || sizeof(int32_t) > buflen - k) { #if defined(KERNEL) || defined(_KERNEL) if (m == NULL) return 0; A = m_xword(m, k, &merr); if (merr != 0) return 0; continue; #else return 0; #endif } A = EXTRACT_LONG(&p[k]); continue; case BPF_LD|BPF_H|BPF_ABS: k = pc->k; if (k > buflen || sizeof(int16_t) > buflen - k) { #if defined(KERNEL) || defined(_KERNEL) if (m == NULL) return 0; A = m_xhalf(m, k, &merr); if (merr != 0) return 0; continue; #else return 0; #endif } A = EXTRACT_SHORT(&p[k]); continue; case BPF_LD|BPF_B|BPF_ABS: { #if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) int code = BPF_S_ANC_NONE; #define ANCILLARY(CODE) case SKF_AD_OFF + SKF_AD_##CODE: \ code = BPF_S_ANC_##CODE; \ if (!aux_data) \ return 0; \ break; switch (pc->k) { ANCILLARY(VLAN_TAG); ANCILLARY(VLAN_TAG_PRESENT); default : #endif k = pc->k; if (k >= buflen) { #if defined(KERNEL) || defined(_KERNEL) if (m == NULL) return 0; n = m; MINDEX(len, n, k); A = mtod(n, u_char *)[k]; continue; #else return 0; #endif } A = p[k]; #if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) } switch (code) { case BPF_S_ANC_VLAN_TAG: if (aux_data) A = aux_data->vlan_tag; break; case BPF_S_ANC_VLAN_TAG_PRESENT: if (aux_data) A = aux_data->vlan_tag_present; break; } #endif continue; } case BPF_LD|BPF_W|BPF_LEN: A = wirelen; continue; case BPF_LDX|BPF_W|BPF_LEN: X = wirelen; continue; case BPF_LD|BPF_W|BPF_IND: k = X + pc->k; if (pc->k > buflen || X > buflen - pc->k || sizeof(int32_t) > buflen - k) { #if defined(KERNEL) || defined(_KERNEL) if (m == NULL) return 0; A = m_xword(m, k, &merr); if (merr != 0) return 0; continue; #else return 0; #endif } A = EXTRACT_LONG(&p[k]); continue; case BPF_LD|BPF_H|BPF_IND: k = X + pc->k; if (X > buflen || pc->k > buflen - X || sizeof(int16_t) > buflen - k) { #if defined(KERNEL) || defined(_KERNEL) if (m == NULL) return 0; A = m_xhalf(m, k, &merr); if (merr != 0) return 0; continue; #else return 0; #endif } A = EXTRACT_SHORT(&p[k]); continue; case BPF_LD|BPF_B|BPF_IND: k = X + pc->k; if (pc->k >= buflen || X >= buflen - pc->k) { #if defined(KERNEL) || defined(_KERNEL) if (m == NULL) return 0; n = m; MINDEX(len, n, k); A = mtod(n, u_char *)[k]; continue; #else return 0; #endif } A = p[k]; continue; case BPF_LDX|BPF_MSH|BPF_B: k = pc->k; if (k >= buflen) { #if defined(KERNEL) || defined(_KERNEL) if (m == NULL) return 0; n = m; MINDEX(len, n, k); X = (mtod(n, char *)[k] & 0xf) << 2; continue; #else return 0; #endif } X = (p[pc->k] & 0xf) << 2; continue; case BPF_LD|BPF_IMM: A = pc->k; continue; case BPF_LDX|BPF_IMM: X = pc->k; continue; case BPF_LD|BPF_MEM: A = mem[pc->k]; continue; case BPF_LDX|BPF_MEM: X = mem[pc->k]; continue; case BPF_ST: mem[pc->k] = A; continue; case BPF_STX: mem[pc->k] = X; continue; case BPF_JMP|BPF_JA: #if defined(KERNEL) || defined(_KERNEL) /* * No backward jumps allowed. */ pc += pc->k; #else /* * XXX - we currently implement "ip6 protochain" * with backward jumps, so sign-extend pc->k. */ pc += (bpf_int32)pc->k; #endif continue; case BPF_JMP|BPF_JGT|BPF_K: pc += (A > pc->k) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JGE|BPF_K: pc += (A >= pc->k) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JEQ|BPF_K: pc += (A == pc->k) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JSET|BPF_K: pc += (A & pc->k) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JGT|BPF_X: pc += (A > X) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JGE|BPF_X: pc += (A >= X) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JEQ|BPF_X: pc += (A == X) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JSET|BPF_X: pc += (A & X) ? pc->jt : pc->jf; continue; case BPF_ALU|BPF_ADD|BPF_X: A += X; continue; case BPF_ALU|BPF_SUB|BPF_X: A -= X; continue; case BPF_ALU|BPF_MUL|BPF_X: A *= X; continue; case BPF_ALU|BPF_DIV|BPF_X: if (X == 0) return 0; A /= X; continue; case BPF_ALU|BPF_MOD|BPF_X: if (X == 0) return 0; A %= X; continue; case BPF_ALU|BPF_AND|BPF_X: A &= X; continue; case BPF_ALU|BPF_OR|BPF_X: A |= X; continue; case BPF_ALU|BPF_XOR|BPF_X: A ^= X; continue; case BPF_ALU|BPF_LSH|BPF_X: A <<= X; continue; case BPF_ALU|BPF_RSH|BPF_X: A >>= X; continue; case BPF_ALU|BPF_ADD|BPF_K: A += pc->k; continue; case BPF_ALU|BPF_SUB|BPF_K: A -= pc->k; continue; case BPF_ALU|BPF_MUL|BPF_K: A *= pc->k; continue; case BPF_ALU|BPF_DIV|BPF_K: A /= pc->k; continue; case BPF_ALU|BPF_MOD|BPF_K: A %= pc->k; continue; case BPF_ALU|BPF_AND|BPF_K: A &= pc->k; continue; case BPF_ALU|BPF_OR|BPF_K: A |= pc->k; continue; case BPF_ALU|BPF_XOR|BPF_K: A ^= pc->k; continue; case BPF_ALU|BPF_LSH|BPF_K: A <<= pc->k; continue; case BPF_ALU|BPF_RSH|BPF_K: A >>= pc->k; continue; case BPF_ALU|BPF_NEG: /* * Most BPF arithmetic is unsigned, but negation * can't be unsigned; throw some casts to * specify what we're trying to do. */ A = (u_int32)(-(int32)A); continue; case BPF_MISC|BPF_TAX: X = A; continue; case BPF_MISC|BPF_TXA: A = X; continue; } } } u_int bpf_filter(pc, p, wirelen, buflen) register const struct bpf_insn *pc; register const u_char *p; u_int wirelen; register u_int buflen; { return bpf_filter_with_aux_data(pc, p, wirelen, buflen, NULL); } /* * Return true if the 'fcode' is a valid filter program. * The constraints are that each jump be forward and to a valid * code, that memory accesses are within valid ranges (to the * extent that this can be checked statically; loads of packet * data have to be, and are, also checked at run time), and that * the code terminates with either an accept or reject. * * The kernel needs to be able to verify an application's filter code. * Otherwise, a bogus program could easily crash the system. */ int bpf_validate(f, len) const struct bpf_insn *f; int len; { u_int i, from; const struct bpf_insn *p; if (len < 1) return 0; /* * There's no maximum program length in userland. */ #if defined(KERNEL) || defined(_KERNEL) if (len > BPF_MAXINSNS) return 0; #endif for (i = 0; i < (u_int)len; ++i) { p = &f[i]; switch (BPF_CLASS(p->code)) { /* * Check that memory operations use valid addresses. */ case BPF_LD: case BPF_LDX: switch (BPF_MODE(p->code)) { case BPF_IMM: break; case BPF_ABS: case BPF_IND: case BPF_MSH: /* * There's no maximum packet data size * in userland. The runtime packet length * check suffices. */ #if defined(KERNEL) || defined(_KERNEL) /* * More strict check with actual packet length * is done runtime. */ if (p->k >= bpf_maxbufsize) return 0; #endif break; case BPF_MEM: if (p->k >= BPF_MEMWORDS) return 0; break; case BPF_LEN: break; default: return 0; } break; case BPF_ST: case BPF_STX: if (p->k >= BPF_MEMWORDS) return 0; break; case BPF_ALU: switch (BPF_OP(p->code)) { case BPF_ADD: case BPF_SUB: case BPF_MUL: case BPF_OR: case BPF_AND: case BPF_XOR: case BPF_LSH: case BPF_RSH: case BPF_NEG: break; case BPF_DIV: case BPF_MOD: /* * Check for constant division or modulus * by 0. */ if (BPF_SRC(p->code) == BPF_K && p->k == 0) return 0; break; default: return 0; } break; case BPF_JMP: /* * Check that jumps are within the code block, * and that unconditional branches don't go * backwards as a result of an overflow. * Unconditional branches have a 32-bit offset, * so they could overflow; we check to make * sure they don't. Conditional branches have * an 8-bit offset, and the from address is <= * BPF_MAXINSNS, and we assume that BPF_MAXINSNS * is sufficiently small that adding 255 to it * won't overflow. * * We know that len is <= BPF_MAXINSNS, and we * assume that BPF_MAXINSNS is < the maximum size * of a u_int, so that i + 1 doesn't overflow. * * For userland, we don't know that the from * or len are <= BPF_MAXINSNS, but we know that * from <= len, and, except on a 64-bit system, * it's unlikely that len, if it truly reflects * the size of the program we've been handed, * will be anywhere near the maximum size of * a u_int. We also don't check for backward * branches, as we currently support them in * userland for the protochain operation. */ from = i + 1; switch (BPF_OP(p->code)) { case BPF_JA: #if defined(KERNEL) || defined(_KERNEL) if (from + p->k < from || from + p->k >= len) #else if (from + p->k >= (u_int)len) #endif return 0; break; case BPF_JEQ: case BPF_JGT: case BPF_JGE: case BPF_JSET: if (from + p->jt >= (u_int)len || from + p->jf >= (u_int)len) return 0; break; default: return 0; } break; case BPF_RET: break; case BPF_MISC: break; default: return 0; } } return BPF_CLASS(f[len - 1].code) == BPF_RET; } libpcap-1.8.1/pcap.3pcap.in0000644000026300017510000007002713003771737013554 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP 3PCAP "8 March 2015" .SH NAME pcap \- Packet Capture library .SH SYNOPSIS .nf .ft B #include .LP .ft B .ft .fi .SH DESCRIPTION The Packet Capture library provides a high level interface to packet capture systems. All packets on the network, even those destined for other hosts, are accessible through this mechanism. It also supports saving captured packets to a ``savefile'', and reading packets from a ``savefile''. .SS Opening a capture handle for reading To open a handle for a live capture, given the name of the network or other interface on which the capture should be done, call .BR pcap_create (), set the appropriate options on the handle, and then activate it with .BR pcap_activate (). .PP To obtain a list of devices that can be opened for a live capture, call .BR pcap_findalldevs (); to free the list returned by .BR pcap_findalldevs (), call .BR pcap_freealldevs (). .BR pcap_lookupdev () will return the first device on that list that is not a ``loopback`` network interface. .PP To open a handle for a ``savefile'' from which to read packets, given the pathname of the ``savefile'', call .BR pcap_open_offline (); to set up a handle for a ``savefile'', given a .B "FILE\ *" referring to a file already opened for reading, call .BR pcap_fopen_offline (). .PP In order to get a ``fake'' .B pcap_t for use in routines that require a .B pcap_t as an argument, such as routines to open a ``savefile'' for writing and to compile a filter expression, call .BR pcap_open_dead (). .PP .BR pcap_create (), .BR pcap_open_offline (), .BR pcap_fopen_offline (), and .BR pcap_open_dead () return a pointer to a .BR pcap_t , which is the handle used for reading packets from the capture stream or the ``savefile'', and for finding out information about the capture stream or ``savefile''. To close a handle, use .BR pcap_close (). .PP The options that can be set on a capture handle include .IP "snapshot length" If, when capturing, you capture the entire contents of the packet, that requires more CPU time to copy the packet to your application, more disk and possibly network bandwidth to write the packet data to a file, and more disk space to save the packet. If you don't need the entire contents of the packet - for example, if you are only interested in the TCP headers of packets - you can set the "snapshot length" for the capture to an appropriate value. If the snapshot length is set to .IR snaplen , and .I snaplen is less than the size of a packet that is captured, only the first .I snaplen bytes of that packet will be captured and provided as packet data. .IP A snapshot length of 65535 should be sufficient, on most if not all networks, to capture all the data available from the packet. .IP The snapshot length is set with .BR pcap_set_snaplen (). .IP "promiscuous mode" On broadcast LANs such as Ethernet, if the network isn't switched, or if the adapter is connected to a "mirror port" on a switch to which all packets passing through the switch are sent, a network adapter receives all packets on the LAN, including unicast or multicast packets not sent to a network address that the network adapter isn't configured to recognize. .IP Normally, the adapter will discard those packets; however, many network adapters support "promiscuous mode", which is a mode in which all packets, even if they are not sent to an address that the adapter recognizes, are provided to the host. This is useful for passively capturing traffic between two or more other hosts for analysis. .IP Note that even if an application does not set promiscuous mode, the adapter could well be in promiscuous mode for some other reason. .IP For now, this doesn't work on the "any" device; if an argument of "any" or NULL is supplied, the setting of promiscuous mode is ignored. .IP Promiscuous mode is set with .BR pcap_set_promisc (). .IP "monitor mode" On IEEE 802.11 wireless LANs, even if an adapter is in promiscuous mode, it will supply to the host only frames for the network with which it's associated. It might also supply only data frames, not management or control frames, and might not provide the 802.11 header or radio information pseudo-header for those frames. .IP In "monitor mode", sometimes also called "rfmon mode" (for "Radio Frequency MONitor"), the adapter will supply all frames that it receives, with 802.11 headers, and might supply a pseudo-header with radio information about the frame as well. .IP Note that in monitor mode the adapter might disassociate from the network with which it's associated, so that you will not be able to use any wireless networks with that adapter. This could prevent accessing files on a network server, or resolving host names or network addresses, if you are capturing in monitor mode and are not connected to another network with another adapter. .IP Monitor mode is set with .BR pcap_set_rfmon (), and .BR pcap_can_set_rfmon () can be used to determine whether an adapter can be put into monitor mode. .IP "read timeout" If, when capturing, packets are delivered as soon as they arrive, the application capturing the packets will be woken up for each packet as it arrives, and might have to make one or more calls to the operating system to fetch each packet. .IP If, instead, packets are not delivered as soon as they arrive, but are delivered after a short delay (called a "read timeout"), more than one packet can be accumulated before the packets are delivered, so that a single wakeup would be done for multiple packets, and each set of calls made to the operating system would supply multiple packets, rather than a single packet. This reduces the per-packet CPU overhead if packets are arriving at a high rate, increasing the number of packets per second that can be captured. .IP The read timeout is required so that an application won't wait for the operating system's capture buffer to fill up before packets are delivered; if packets are arriving slowly, that wait could take an arbitrarily long period of time. .IP Not all platforms support a read timeout; on platforms that don't, the read timeout is ignored. A zero value for the timeout, on platforms that support a read timeout, will cause a read to wait forever to allow enough packets to arrive, with no timeout. .IP .BR NOTE : the read timeout cannot be used to cause calls that read packets to return within a limited period of time, because, on some platforms, the read timeout isn't supported, and, on other platforms, the timer doesn't start until at least one packet arrives. This means that the read timeout should .B NOT be used, for example, in an interactive application to allow the packet capture loop to ``poll'' for user input periodically, as there's no guarantee that a call reading packets will return after the timeout expires even if no packets have arrived. .IP The read timeout is set with .BR pcap_set_timeout (). .IP "buffer size" Packets that arrive for a capture are stored in a buffer, so that they do not have to be read by the application as soon as they arrive. On some platforms, the buffer's size can be set; a size that's too small could mean that, if too many packets are being captured and the snapshot length doesn't limit the amount of data that's buffered, packets could be dropped if the buffer fills up before the application can read packets from it, while a size that's too large could use more non-pageable operating system memory than is necessary to prevent packets from being dropped. .IP The buffer size is set with .BR pcap_set_buffer_size (). .IP "timestamp type" On some platforms, the time stamp given to packets on live captures can come from different sources that can have different resolutions or that can have different relationships to the time values for the current time supplied by routines on the native operating system. See .BR pcap-tstamp (@MAN_MISC_INFO@) for a list of time stamp types. .IP The time stamp type is set with .BR pcap_set_tstamp_type (). .PP Reading packets from a network interface may require that you have special privileges: .TP .B Under SunOS 3.x or 4.x with NIT or BPF: You must have read access to .I /dev/nit or .IR /dev/bpf* . .TP .B Under Solaris with DLPI: You must have read/write access to the network pseudo device, e.g. .IR /dev/le . On at least some versions of Solaris, however, this is not sufficient to allow .I tcpdump to capture in promiscuous mode; on those versions of Solaris, you must be root, or the application capturing packets must be installed setuid to root, in order to capture in promiscuous mode. Note that, on many (perhaps all) interfaces, if you don't capture in promiscuous mode, you will not see any outgoing packets, so a capture not done in promiscuous mode may not be very useful. .IP In newer versions of Solaris, you must have been given the .B net_rawaccess privilege; this is both necessary and sufficient to give you access to the network pseudo-device - there is no need to change the privileges on that device. A user can be given that privilege by, for example, adding that privilege to the user's .B defaultpriv key with the .B usermod (1M) command. .TP .B Under HP-UX with DLPI: You must be root or the application capturing packets must be installed setuid to root. .TP .B Under IRIX with snoop: You must be root or the application capturing packets must be installed setuid to root. .TP .B Under Linux: You must be root or the application capturing packets must be installed setuid to root (unless your distribution has a kernel that supports capability bits such as CAP_NET_RAW and code to allow those capability bits to be given to particular accounts and to cause those bits to be set on a user's initial processes when they log in, in which case you must have CAP_NET_RAW in order to capture and CAP_NET_ADMIN to enumerate network devices with, for example, the .B \-D flag). .TP .B Under ULTRIX and Digital UNIX/Tru64 UNIX: Any user may capture network traffic. However, no user (not even the super-user) can capture in promiscuous mode on an interface unless the super-user has enabled promiscuous-mode operation on that interface using .IR pfconfig (8), and no user (not even the super-user) can capture unicast traffic received by or sent by the machine on an interface unless the super-user has enabled copy-all-mode operation on that interface using .IR pfconfig , so .I useful packet capture on an interface probably requires that either promiscuous-mode or copy-all-mode operation, or both modes of operation, be enabled on that interface. .TP .B Under BSD (this includes Mac OS X): You must have read access to .I /dev/bpf* on systems that don't have a cloning BPF device, or to .I /dev/bpf on systems that do. On BSDs with a devfs (this includes Mac OS X), this might involve more than just having somebody with super-user access setting the ownership or permissions on the BPF devices - it might involve configuring devfs to set the ownership or permissions every time the system is booted, if the system even supports that; if it doesn't support that, you might have to find some other way to make that happen at boot time. .PP Reading a saved packet file doesn't require special privileges. .PP The packets read from the handle may include a ``pseudo-header'' containing various forms of packet meta-data, and probably includes a link-layer header whose contents can differ for different network interfaces. To determine the format of the packets supplied by the handle, call .BR pcap_datalink (); .I http://www.tcpdump.org/linktypes.html lists the values it returns and describes the packet formats that correspond to those values. .PP Do .B NOT assume that the packets for a given capture or ``savefile`` will have any given link-layer header type, such as .B DLT_EN10MB for Ethernet. For example, the "any" device on Linux will have a link-layer header type of .B DLT_LINUX_SLL even if all devices on the system at the time the "any" device is opened have some other data link type, such as .B DLT_EN10MB for Ethernet. .PP To obtain the .B "FILE\ *" corresponding to a .B pcap_t opened for a ``savefile'', call .BR pcap_file (). .TP .B Routines .RS .TP .BR pcap_create (3PCAP) get a .B pcap_t for live capture .TP .BR pcap_activate (3PCAP) activate a .B pcap_t for live capture .TP .BR pcap_findalldevs (3PCAP) get a list of devices that can be opened for a live capture .TP .BR pcap_freealldevs (3PCAP) free list of devices .TP .BR pcap_lookupdev (3PCAP) get first non-loopback device on that list .TP .BR pcap_open_offline (3PCAP) open a .B pcap_t for a ``savefile'', given a pathname .TP .BR pcap_open_offline_with_tstamp_precision (3PCAP) open a .B pcap_t for a ``savefile'', given a pathname, and specify the precision to provide for packet time stamps .TP .BR pcap_fopen_offline (3PCAP) open a .B pcap_t for a ``savefile'', given a .B "FILE\ *" .TP .BR pcap_fopen_offline_with_tstamp_precision (3PCAP) open a .B pcap_t for a ``savefile'', given a .BR "FILE\ *" , and specify the precision to provide for packet time stamps .TP .BR pcap_open_dead (3PCAP) create a ``fake'' .B pcap_t .TP .BR pcap_close (3PCAP) close a .B pcap_t .TP .BR pcap_set_snaplen (3PCAP) set the snapshot length for a not-yet-activated .B pcap_t for live capture .TP .BR pcap_snapshot (3PCAP) get the snapshot length for a .B pcap_t .TP .BR pcap_set_promisc (3PCAP) set promiscuous mode for a not-yet-activated .B pcap_t for live capture .TP .BR pcap_set_rfmon (3PCAP) set monitor mode for a not-yet-activated .B pcap_t for live capture .TP .BR pcap_can_set_rfmon (3PCAP) determine whether monitor mode can be set for a .B pcap_t for live capture .TP .BR pcap_set_timeout (3PCAP) set read timeout for a not-yet-activated .B pcap_t for live capture .TP .BR pcap_set_buffer_size (3PCAP) set buffer size for a not-yet-activated .B pcap_t for live capture .TP .BR pcap_set_tstamp_type (3PCAP) set time stamp type for a not-yet-activated .B pcap_t for live capture .TP .BR pcap_list_tstamp_types (3PCAP) get list of available time stamp types for a not-yet-activated .B pcap_t for live capture .TP .BR pcap_free_tstamp_types (3PCAP) free list of available time stamp types .TP .BR pcap_tstamp_type_val_to_name (3PCAP) get name for a time stamp type .TP .BR pcap_tstamp_type_val_to_description (3PCAP) get description for a time stamp type .TP .BR pcap_tstamp_type_name_to_val (3PCAP) get time stamp type corresponding to a name .TP .BR pcap_set_tstamp_precision (3PCAP) set time stamp precision for a not-yet-activated .B pcap_t for live capture .TP .BR pcap_get_tstamp_precision (3PCAP) get the time stamp precision of a .B pcap_t for live capture .TP .BR pcap_datalink (3PCAP) get link-layer header type for a .B pcap_t .TP .BR pcap_file (3PCAP) get the .B "FILE\ *" for a .B pcap_t opened for a ``savefile'' .TP .BR pcap_is_swapped (3PCAP) determine whether a ``savefile'' being read came from a machine with the opposite byte order .TP .BR pcap_major_version (3PCAP) .PD 0 .TP .BR pcap_minor_version (3PCAP) get the major and minor version of the file format version for a ``savefile'' .PD .RE .SS Selecting a link-layer header type for a live capture Some devices may provide more than one link-layer header type. To obtain a list of all link-layer header types provided by a device, call .BR pcap_list_datalinks () on an activated .B pcap_t for the device. To free a list of link-layer header types, call .BR pcap_free_datalinks (). To set the link-layer header type for a device, call .BR pcap_set_datalink (). This should be done after the device has been activated but before any packets are read and before any filters are compiled or installed. .TP .B Routines .RS .TP .BR pcap_list_datalinks (3PCAP) get a list of link-layer header types for a device .TP .BR pcap_free_datalinks (3PCAP) free list of link-layer header types .TP .BR pcap_set_datalink (3PCAP) set link-layer header type for a device .TP .BR pcap_datalink_val_to_name (3PCAP) get name for a link-layer header type .TP .BR pcap_datalink_val_to_description (3PCAP) get description for a link-layer header type .TP .BR pcap_datalink_name_to_val (3PCAP) get link-layer header type corresponding to a name .RE .SS Reading packets Packets are read with .BR pcap_dispatch () or .BR pcap_loop (), which process one or more packets, calling a callback routine for each packet, or with .BR pcap_next () or .BR pcap_next_ex (), which return the next packet. The callback for .BR pcap_dispatch () and .BR pcap_loop () is supplied a pointer to a .IR "struct pcap_pkthdr" , which includes the following members: .RS .TP .B ts a .I struct timeval containing the time when the packet was captured .TP .B caplen a .I bpf_u_int32 giving the number of bytes of the packet that are available from the capture .TP .B len a .I bpf_u_int32 giving the length of the packet, in bytes (which might be more than the number of bytes available from the capture, if the length of the packet is larger than the maximum number of bytes to capture). .RE .PP The callback is also supplied a .I const u_char pointer to the first .B caplen (as given in the .I struct pcap_pkthdr mentioned above) bytes of data from the packet. This won't necessarily be the entire packet; to capture the entire packet, you will have to provide a value for .I snaplen in your call to .BR pcap_set_snaplen () that is sufficiently large to get all of the packet's data - a value of 65535 should be sufficient on most if not all networks). When reading from a ``savefile'', the snapshot length specified when the capture was performed will limit the amount of packet data available. .PP .BR pcap_next () is passed an argument that points to a .I struct pcap_pkthdr structure, and fills it in with the time stamp and length values for the packet. It returns a .I const u_char to the first .B caplen bytes of the packet on success, and NULL on error. .PP .BR pcap_next_ex () is passed two pointer arguments, one of which points to a .IR struct pcap_pkthdr * and one of which points to a .IR "const u_char" *. It sets the first pointer to point to a .I struct pcap_pkthdr structure with the time stamp and length values for the packet, and sets the second pointer to point to the first .B caplen bytes of the packet. .PP To force the loop in .BR pcap_dispatch () or .BR pcap_loop () to terminate, call .BR pcap_breakloop (). .PP By default, when reading packets from an interface opened for a live capture, .BR pcap_dispatch (), .BR pcap_next (), and .BR pcap_next_ex () will, if no packets are currently available to be read, block waiting for packets to become available. On some, but .I not all, platforms, if a read timeout was specified, the wait will terminate after the read timeout expires; applications should be prepared for this, as it happens on some platforms, but should not rely on it, as it does not happen on other platforms. Note that the wait might, or might not, terminate even if no packets are available; applications should be prepared for this to happen, but must not rely on it happening. .PP A handle can be put into ``non-blocking mode'', so that those routines will, rather than blocking, return an indication that no packets are available to read. Call .BR pcap_setnonblock () to put a handle into non-blocking mode or to take it out of non-blocking mode; call .BR pcap_getnonblock () to determine whether a handle is in non-blocking mode. Note that non-blocking mode does not work correctly in Mac OS X 10.6. .PP Non-blocking mode is often combined with routines such as .BR select (2) or .BR poll (2) or other routines a platform offers to wait for any of a set of descriptors to be ready to read. To obtain, for a handle, a descriptor that can be used in those routines, call .BR pcap_get_selectable_fd (). Not all handles have such a descriptor available; .BR pcap_get_selectable_fd () will return \-1 if no such descriptor exists. In addition, for various reasons, one or more of those routines will not work properly with the descriptor; the documentation for .BR pcap_get_selectable_fd () gives details. Note that, just as an attempt to read packets from a .B pcap_t may not return any packets if the read timeout expires, a .BR select (), .BR poll (), or other such call may, if the read timeout expires, indicate that a descriptor is ready to read even if there are no packets available to read. .TP .B Routines .RS .TP .BR pcap_dispatch (3PCAP) read a bufferful of packets from a .B pcap_t open for a live capture or the full set of packets from a .B pcap_t open for a ``savefile'' .TP .BR pcap_loop (3PCAP) read packets from a .B pcap_t until an interrupt or error occurs .TP .BR pcap_next (3PCAP) read the next packet from a .B pcap_t without an indication whether an error occurred .TP .BR pcap_next_ex (3PCAP) read the next packet from a .B pcap_t with an error indication on an error .TP .BR pcap_breakloop (3PCAP) prematurely terminate the loop in .BR pcap_dispatch () or .BR pcap_loop () .TP .BR pcap_setnonblock (3PCAP) set or clear non-blocking mode on a .B pcap_t .TP .BR pcap_getnonblock (3PCAP) get the state of non-blocking mode for a .B pcap_t .TP .BR pcap_get_selectable_fd (3PCAP) attempt to get a descriptor for a .B pcap_t that can be used in calls such as .BR select (2) and .BR poll (2) .RE .SS Filters In order to cause only certain packets to be returned when reading packets, a filter can be set on a handle. For a live capture, the filtering will be performed in kernel mode, if possible, to avoid copying ``uninteresting'' packets from the kernel to user mode. .PP A filter can be specified as a text string; the syntax and semantics of the string are as described by .BR pcap-filter (@MAN_MISC_INFO@). A filter string is compiled into a program in a pseudo-machine-language by .BR pcap_compile () and the resulting program can be made a filter for a handle with .BR pcap_setfilter (). The result of .BR pcap_compile () can be freed with a call to .BR pcap_freecode (). .BR pcap_compile () may require a network mask for certain expressions in the filter string; .BR pcap_lookupnet () can be used to find the network address and network mask for a given capture device. .PP A compiled filter can also be applied directly to a packet that has been read using .BR pcap_offline_filter (). .TP .B Routines .RS .TP .BR pcap_compile (3PCAP) compile filter expression to a pseudo-machine-language code program .TP .BR pcap_freecode (3PCAP) free a filter program .TP .BR pcap_setfilter (3PCAP) set filter for a .B pcap_t .TP .BR pcap_lookupnet (3PCAP) get network address and network mask for a capture device .TP .BR pcap_offline_filter (3PCAP) apply a filter program to a packet .RE .SS Incoming and outgoing packets By default, libpcap will attempt to capture both packets sent by the machine and packets received by the machine. To limit it to capturing only packets received by the machine or, if possible, only packets sent by the machine, call .BR pcap_setdirection (). .TP .BR Routines .RS .TP .BR pcap_setdirection (3PCAP) specify whether to capture incoming packets, outgoing packets, or both .RE .SS Capture statistics To get statistics about packets received and dropped in a live capture, call .BR pcap_stats (). .TP .B Routines .RS .TP .BR pcap_stats (3PCAP) get capture statistics .RE .SS Opening a handle for writing captured packets To open a ``savefile`` to which to write packets, given the pathname the ``savefile'' should have, call .BR pcap_dump_open (). To open a ``savefile`` to which to write packets, given the pathname the ``savefile'' should have, call .BR pcap_dump_open (); to set up a handle for a ``savefile'', given a .B "FILE\ *" referring to a file already opened for writing, call .BR pcap_dump_fopen (). They each return pointers to a .BR pcap_dumper_t , which is the handle used for writing packets to the ``savefile''. If it succeeds, it will have created the file if it doesn't exist and truncated the file if it does exist. To close a .BR pcap_dumper_t , call .BR pcap_dump_close (). .TP .B Routines .RS .TP .BR pcap_dump_open (3PCAP) open a .B pcap_dumper_t for a ``savefile``, given a pathname .TP .BR pcap_dump_fopen (3PCAP) open a .B pcap_dumper_t for a ``savefile``, given a .B "FILE\ *" .TP .BR pcap_dump_close (3PCAP) close a .B pcap_dumper_t .TP .BR pcap_dump_file (3PCAP) get the .B "FILE\ *" for a .B pcap_dumper_t opened for a ``savefile'' .RE .SS Writing packets To write a packet to a .BR pcap_dumper_t , call .BR pcap_dump (). Packets written with .BR pcap_dump () may be buffered, rather than being immediately written to the ``savefile''. Closing the .B pcap_dumper_t will cause all buffered-but-not-yet-written packets to be written to the ``savefile''. To force all packets written to the .BR pcap_dumper_t , and not yet written to the ``savefile'' because they're buffered by the .BR pcap_dumper_t , to be written to the ``savefile'', without closing the .BR pcap_dumper_t , call .BR pcap_dump_flush (). .TP .B Routines .RS .TP .BR pcap_dump (3PCAP) write packet to a .B pcap_dumper_t .TP .BR pcap_dump_flush (3PCAP) flush buffered packets written to a .B pcap_dumper_t to the ``savefile'' .TP .BR pcap_dump_ftell (3PCAP) get current file position for a .B pcap_dumper_t .RE .SS Injecting packets If you have the required privileges, you can inject packets onto a network with a .B pcap_t for a live capture, using .BR pcap_inject () or .BR pcap_sendpacket (). (The two routines exist for compatibility with both OpenBSD and WinPcap; they perform the same function, but have different return values.) .TP .B Routines .RS .TP .BR pcap_inject (3PCAP) .PD 0 .TP .BR pcap_sendpacket (3PCAP) transmit a packet .PD .RE .SS Reporting errors Some routines return error or warning status codes; to convert them to a string, use .BR pcap_statustostr (). .TP .B Routines .RS .TP .BR pcap_statustostr (3PCAP) get a string for an error or warning status code .RE .SS Getting library version information To get a string giving version information about libpcap, call .BR pcap_lib_version (). .TP .B Routines .RS .TP .BR pcap_lib_version (3PCAP) get library version string .RE .SH BACKWARDS COMPATIBILITY .PP In versions of libpcap prior to 1.0, the .B pcap.h header file was not in a .B pcap directory on most platforms; if you are writing an application that must work on versions of libpcap prior to 1.0, include .BR , which will include .B for you, rather than including .BR . .PP .BR pcap_create () and .BR pcap_activate () were not available in versions of libpcap prior to 1.0; if you are writing an application that must work on versions of libpcap prior to 1.0, either use .BR pcap_open_live () to get a handle for a live capture or, if you want to be able to use the additional capabilities offered by using .BR pcap_create () and .BR pcap_activate (), use an .BR autoconf (1) script or some other configuration script to check whether the libpcap 1.0 APIs are available and use them only if they are. .SH SEE ALSO autoconf(1), tcpdump(1), tcpslice(1), pcap-filter(@MAN_MISC_INFO@), pfconfig(8), usermod(1M) .SH AUTHORS The original authors of libpcap are: .LP Van Jacobson, Craig Leres and Steven McCanne, all of the Lawrence Berkeley National Laboratory, University of California, Berkeley, CA. .LP The current version is available from "The Tcpdump Group"'s Web site at .LP .RS .I http://www.tcpdump.org/ .RE .SH BUGS Please send problems, bugs, questions, desirable enhancements, etc. to: .LP .RS tcpdump-workers@lists.tcpdump.org .RE libpcap-1.8.1/pcap_snapshot.3pcap0000644000026300017510000000361413003771737015064 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_SNAPSHOT 3PCAP "7 April 2014" .SH NAME pcap_snapshot \- get the snapshot length .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_snapshot(pcap_t *p); .ft .fi .SH DESCRIPTION .B pcap_snapshot() returns the snapshot length specified when .B pcap_set_snapshot() or .B pcap_open_live() was called, for a live capture, or the snapshot length from the capture file, for a ``savefile''. .PP It must not be called on a pcap descriptor created by .B pcap_create() that has not yet been activated by .BR pcap_activate() . .SH RETURN VALUE .B pcap_snapshot() returns the snapshot length on success and .B PCAP_ERROR_NOT_ACTIVATED if called on a capture handle that has been created but not activated. .SH SEE ALSO pcap(3PCAP) libpcap-1.8.1/pcap_geterr.3pcap0000644000026300017510000000352713003771737014520 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_GETERR 3PCAP "3 January 2014" .SH NAME pcap_geterr, pcap_perror \- get or print libpcap error message text .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B char *pcap_geterr(pcap_t *p); void pcap_perror(pcap_t *p, const char *prefix); .ft .fi .SH DESCRIPTION .B pcap_geterr() returns the error text pertaining to the last pcap library error. .BR NOTE : the pointer it returns will no longer point to a valid error message string after the .B pcap_t passed to it is closed; you must use or copy the string before closing the .BR pcap_t . .PP .B pcap_perror() prints the text of the last pcap library error on .BR stderr , prefixed by .IR prefix . .SH SEE ALSO pcap(3PCAP) libpcap-1.8.1/pcap-savefile.manfile.in0000644000026300017510000001221713003771737015752 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP-SAVEFILE @MAN_FILE_FORMATS@ "8 March 2015" .SH NAME pcap-savefile \- libpcap savefile format .SH DESCRIPTION NOTE: applications and libraries should, if possible, use libpcap to read savefiles, rather than having their own code to read savefiles. If, in the future, a new file format is supported by libpcap, applications and libraries using libpcap to read savefiles will be able to read the new format of savefiles, but applications and libraries using their own code to read savefiles will have to be changed to support the new file format. .PP ``Savefiles'' read and written by libpcap and applications using libpcap start with a per-file header. The format of the per-file header is: .RS .TS box; c s c | c c s. Magic number _ Major version Minor version _ Time zone offset _ Time stamp accuracy _ Snapshot length _ Link-layer header type .TE .RE .PP All fields in the per-file header are in the byte order of the host writing the file. Normally, the first field in the per-file header is a 4-byte magic number, with the value 0xa1b2c3d4. The magic number, when read by a host with the same byte order as the host that wrote the file, will have the value 0xa1b2c3d4, and, when read by a host with the opposite byte order as the host that wrote the file, will have the value 0xd4c3b2a1. That allows software reading the file to determine whether the byte order of the host that wrote the file is the same as the byte order of the host on which the file is being read, and thus whether the values in the per-file and per-packet headers need to be byte-swapped. .PP If the magic number has the value 0xa1b23c4d (with the two nibbles of the two lower-order bytes of the magic number swapped), which would be read as 0xa1b23c4d by a host with the same byte order as the host that wrote the file and as 0x4d3cb2a1 by a host with the opposite byte order as the host that wrote the file, the file format is the same as for regular files, except that the time stamps for packets are given in seconds and nanoseconds rather than seconds and microseconds. .PP Following this are: .IP A 2-byte file format major version number; the current version number is 2. .IP A 2-byte file format minor version number; the current version number is 4. .IP A 4-byte time zone offset; this is always 0. .IP A 4-byte number giving the accuracy of time stamps in the file; this is always 0. .IP A 4-byte number giving the "snapshot length" of the capture; packets longer than the snapshot length are truncated to the snapshot length, so that, if the snapshot length is .IR N , only the first .I N bytes of a packet longer than .I N bytes will be saved in the capture. .IP a 4-byte number giving the link-layer header type for packets in the capture; see .BR pcap-linktype (@MAN_MISC_INFO@) for the .B LINKTYPE_ values that can appear in this field. .PP Following the per-file header are zero or more packets; each packet begins with a per-packet header, which is immediately followed by the raw packet data. The format of the per-packet header is: .RS .TS box; c. Time stamp, seconds value _ Time stamp, microseconds or nanoseconds value _ Length of captured packet data _ Un-truncated length of the packet data .TE .RE .PP All fields in the per-packet header are in the byte order of the host writing the file. The per-packet header begins with a time stamp giving the approximate time the packet was captured; the time stamp consists of a 4-byte value, giving the time in seconds since January 1, 1970, 00:00:00 UTC, followed by a 4-byte value, giving the time in microseconds or nanoseconds since that second, depending on the magic number in the file header. Following that are a 4-byte value giving the number of bytes of captured data that follow the per-packet header and a 4-byte value giving the number of bytes that would have been present had the packet not been truncated by the snapshot length. The two lengths will be equal if the number of bytes of packet data are less than or equal to the snapshot length. .SH SEE ALSO pcap(3PCAP), pcap-linktype(@MAN_MISC_INFO@) libpcap-1.8.1/pcap_breakloop.3pcap0000644000026300017510000000731313003771737015203 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_BREAKLOOP 3PCAP "8 March 2015" .SH NAME pcap_breakloop \- force a pcap_dispatch() or pcap_loop() call to return .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B void pcap_breakloop(pcap_t *); .ft .fi .SH DESCRIPTION .B pcap_breakloop() sets a flag that will force .B pcap_dispatch() or .B pcap_loop() to return rather than looping; they will return the number of packets that have been processed so far, or \-2 if no packets have been processed so far. .PP This routine is safe to use inside a signal handler on UNIX or a console control handler on Windows, as it merely sets a flag that is checked within the loop. .PP The flag is checked in loops reading packets from the OS - a signal by itself will not necessarily terminate those loops - as well as in loops processing a set of packets returned by the OS. .ft B Note that if you are catching signals on UNIX systems that support restarting system calls after a signal, and calling pcap_breakloop() in the signal handler, you must specify, when catching those signals, that system calls should NOT be restarted by that signal. Otherwise, if the signal interrupted a call reading packets in a live capture, when your signal handler returns after calling pcap_breakloop(), the call will be restarted, and the loop will not terminate until more packets arrive and the call completes. .ft R .PP .ft B Note also that, in a multi-threaded application, if one thread is blocked in pcap_dispatch(), pcap_loop(), pcap_next(), or pcap_next_ex(), a call to pcap_breakloop() in a different thread will not unblock that thread; you will need to use whatever mechanism the OS provides for breaking a thread out of blocking calls in order to unblock the thread, such as thread cancellation in systems that support POSIX threads. .ft R .PP Note that .B pcap_next() and .B pcap_next_ex() will, on some platforms, loop reading packets from the OS; that loop will not necessarily be terminated by a signal, so .B pcap_breakloop() should be used to terminate packet processing even if .B pcap_next() or .B pcap_next_ex() is being used. .PP .B pcap_breakloop() does not guarantee that no further packets will be processed by .B pcap_dispatch() or .B pcap_loop() after it is called; at most one more packet might be processed. .PP If \-2 is returned from .B pcap_dispatch() or .BR pcap_loop() , the flag is cleared, so a subsequent call will resume reading packets. If a positive number is returned, the flag is not cleared, so a subsequent call will return \-2 and clear the flag. .SH SEE ALSO pcap(3PCAP), pcap_loop(3PCAP), pcap_next_ex(3PCAP) libpcap-1.8.1/scanner.l0000644000026300017510000003031213003771737013073 0ustar mcrmcr%top { /* Must come first for _LARGE_FILE_API on AIX. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif } /* * We want a reentrant scanner. */ %option reentrant /* * And we need to pass the compiler state to the scanner. */ %option extra-type="compiler_state_t *" /* * We don't use input, so don't generate code for it. */ %option noinput /* * We don't use unput, so don't generate code for it. */ %option nounput /* * We don't read from the terminal. */ %option never-interactive /* * We want to stop processing when we get to the end of the input. */ %option noyywrap /* * We want to generate code that can be used by a reentrant parser * generated by Bison or Berkeley YACC. */ %option bison-bridge %{ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * 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. */ #ifdef _WIN32 #include #else #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_BITYPES_H #include #endif #include #endif #include #include #include "pcap-int.h" #include "gencode.h" #include "grammar.h" /* * Earlier versions of Flex don't declare these, so we declare them * ourselves to squelch warnings. */ int pcap_get_column(yyscan_t); void pcap_set_column(int, yyscan_t); #ifdef INET6 #ifdef _WIN32 /* * To quote the MSDN page for getaddrinfo() at * * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx * * "Support for getaddrinfo on Windows 2000 and older versions * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and * later. To execute an application that uses this function on earlier * versions of Windows, then you need to include the Ws2tcpip.h and * Wspiapi.h files. When the Wspiapi.h include file is added, the * getaddrinfo function is defined to the WspiapiGetAddrInfo inline * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo * function is implemented in such a way that if the Ws2_32.dll or the * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology * Preview for Windows 2000) does not include getaddrinfo, then a * version of getaddrinfo is implemented inline based on code in the * Wspiapi.h header file. This inline code will be used on older Windows * platforms that do not natively support the getaddrinfo function." * * We use getaddrinfo(), so we include Wspiapi.h here. pcap-stdinc.h * includes Ws2tcpip.h, so we don't need to include it ourselves. */ #include #else /* _WIN32 */ #include /* for "struct sockaddr" in "struct addrinfo" */ #include /* for "struct addrinfo" */ #endif /* _WIN32 */ /* Workaround for AIX 4.3 */ #if !defined(AI_NUMERICHOST) #define AI_NUMERICHOST 0x04 #endif #endif /*INET6*/ #include #include "grammar.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif static int stoi(char *); static inline int xdtoi(int); %} N ([0-9]+|(0X|0x)[0-9A-Fa-f]+) B ([0-9A-Fa-f][0-9A-Fa-f]?) B2 ([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]) W ([0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?) %a 18400 %o 21500 %e 7600 %k 4550 %p 27600 %n 2000 V680 {W}:{W}:{W}:{W}:{W}:{W}:{W}:{W} V670 ::{W}:{W}:{W}:{W}:{W}:{W}:{W} V671 {W}::{W}:{W}:{W}:{W}:{W}:{W} V672 {W}:{W}::{W}:{W}:{W}:{W}:{W} V673 {W}:{W}:{W}::{W}:{W}:{W}:{W} V674 {W}:{W}:{W}:{W}::{W}:{W}:{W} V675 {W}:{W}:{W}:{W}:{W}::{W}:{W} V676 {W}:{W}:{W}:{W}:{W}:{W}::{W} V677 {W}:{W}:{W}:{W}:{W}:{W}:{W}:: V660 ::{W}:{W}:{W}:{W}:{W}:{W} V661 {W}::{W}:{W}:{W}:{W}:{W} V662 {W}:{W}::{W}:{W}:{W}:{W} V663 {W}:{W}:{W}::{W}:{W}:{W} V664 {W}:{W}:{W}:{W}::{W}:{W} V665 {W}:{W}:{W}:{W}:{W}::{W} V666 {W}:{W}:{W}:{W}:{W}:{W}:: V650 ::{W}:{W}:{W}:{W}:{W} V651 {W}::{W}:{W}:{W}:{W} V652 {W}:{W}::{W}:{W}:{W} V653 {W}:{W}:{W}::{W}:{W} V654 {W}:{W}:{W}:{W}::{W} V655 {W}:{W}:{W}:{W}:{W}:: V640 ::{W}:{W}:{W}:{W} V641 {W}::{W}:{W}:{W} V642 {W}:{W}::{W}:{W} V643 {W}:{W}:{W}::{W} V644 {W}:{W}:{W}:{W}:: V630 ::{W}:{W}:{W} V631 {W}::{W}:{W} V632 {W}:{W}::{W} V633 {W}:{W}:{W}:: V620 ::{W}:{W} V621 {W}::{W} V622 {W}:{W}:: V610 ::{W} V611 {W}:: V600 :: V6604 {W}:{W}:{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} V6504 ::{W}:{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} V6514 {W}::{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} V6524 {W}:{W}::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} V6534 {W}:{W}:{W}::{W}:{W}:{N}\.{N}\.{N}\.{N} V6544 {W}:{W}:{W}:{W}::{W}:{N}\.{N}\.{N}\.{N} V6554 {W}:{W}:{W}:{W}:{W}::{N}\.{N}\.{N}\.{N} V6404 ::{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} V6414 {W}::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} V6424 {W}:{W}::{W}:{W}:{N}\.{N}\.{N}\.{N} V6434 {W}:{W}:{W}::{W}:{N}\.{N}\.{N}\.{N} V6444 {W}:{W}:{W}:{W}::{N}\.{N}\.{N}\.{N} V6304 ::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} V6314 {W}::{W}:{W}:{N}\.{N}\.{N}\.{N} V6324 {W}:{W}::{W}:{N}\.{N}\.{N}\.{N} V6334 {W}:{W}:{W}::{N}\.{N}\.{N}\.{N} V6204 ::{W}:{W}:{N}\.{N}\.{N}\.{N} V6214 {W}::{W}:{N}\.{N}\.{N}\.{N} V6224 {W}:{W}::{N}\.{N}\.{N}\.{N} V6104 ::{W}:{N}\.{N}\.{N}\.{N} V6114 {W}::{N}\.{N}\.{N}\.{N} V6004 ::{N}\.{N}\.{N}\.{N} V6 ({V680}|{V670}|{V671}|{V672}|{V673}|{V674}|{V675}|{V676}|{V677}|{V660}|{V661}|{V662}|{V663}|{V664}|{V665}|{V666}|{V650}|{V651}|{V652}|{V653}|{V654}|{V655}|{V640}|{V641}|{V642}|{V643}|{V644}|{V630}|{V631}|{V632}|{V633}|{V620}|{V621}|{V622}|{V610}|{V611}|{V600}|{V6604}|{V6504}|{V6514}|{V6524}|{V6534}|{V6544}|{V6554}|{V6404}|{V6414}|{V6424}|{V6434}|{V6444}|{V6304}|{V6314}|{V6324}|{V6334}|{V6204}|{V6214}|{V6224}|{V6104}|{V6114}|{V6004}) MAC ({B}:{B}:{B}:{B}:{B}:{B}|{B}\-{B}\-{B}\-{B}\-{B}\-{B}|{B}\.{B}\.{B}\.{B}\.{B}\.{B}|{B2}\.{B2}\.{B2}|{B2}{3}) %% dst return DST; src return SRC; link|ether|ppp|slip return LINK; fddi|tr|wlan return LINK; arp return ARP; rarp return RARP; ip return IP; sctp return SCTP; tcp return TCP; udp return UDP; icmp return ICMP; igmp return IGMP; igrp return IGRP; pim return PIM; vrrp return VRRP; carp return CARP; radio return RADIO; ip6 return IPV6; icmp6 return ICMPV6; ah return AH; esp return ESP; atalk return ATALK; aarp return AARP; decnet return DECNET; lat return LAT; sca return SCA; moprc return MOPRC; mopdl return MOPDL; iso return ISO; esis return ESIS; es-is return ESIS; isis return ISIS; is-is return ISIS; l1 return L1; l2 return L2; iih return IIH; lsp return LSP; snp return SNP; csnp return CSNP; psnp return PSNP; clnp return CLNP; stp return STP; ipx return IPX; netbeui return NETBEUI; host return HOST; net return NET; mask return NETMASK; port return PORT; portrange return PORTRANGE; proto return PROTO; protochain { #ifdef NO_PROTOCHAIN bpf_error(yyextra, "%s not supported", yytext); #else return PROTOCHAIN; #endif } gateway return GATEWAY; type return TYPE; subtype return SUBTYPE; direction|dir return DIR; address1|addr1 return ADDR1; address2|addr2 return ADDR2; address3|addr3 return ADDR3; address4|addr4 return ADDR4; ra return RA; ta return TA; less return LESS; greater return GREATER; byte return CBYTE; broadcast return TK_BROADCAST; multicast return TK_MULTICAST; and|"&&" return AND; or|"||" return OR; not return '!'; len|length return LEN; inbound return INBOUND; outbound return OUTBOUND; vlan return VLAN; mpls return MPLS; pppoed return PPPOED; pppoes return PPPOES; geneve return GENEVE; lane return LANE; llc return LLC; metac return METAC; bcc return BCC; oam return OAM; oamf4 return OAMF4; oamf4ec return OAMF4EC; oamf4sc return OAMF4SC; sc return SC; ilmic return ILMIC; vpi return VPI; vci return VCI; connectmsg return CONNECTMSG; metaconnect return METACONNECT; on|ifname return PF_IFNAME; rset|ruleset return PF_RSET; rnr|rulenum return PF_RNR; srnr|subrulenum return PF_SRNR; reason return PF_REASON; action return PF_ACTION; fisu return FISU; lssu return LSSU; lsu return LSSU; msu return MSU; hfisu return HFISU; hlssu return HLSSU; hmsu return HMSU; sio return SIO; opc return OPC; dpc return DPC; sls return SLS; hsio return HSIO; hopc return HOPC; hdpc return HDPC; hsls return HSLS; [ \r\n\t] ; [+\-*/%:\[\]!<>()&|\^=] return yytext[0]; ">=" return GEQ; "<=" return LEQ; "!=" return NEQ; "==" return '='; "<<" return LSH; ">>" return RSH; ${B} { yylval->e = pcap_ether_aton(((char *)yytext)+1); if (yylval->e == NULL) bpf_error(yyextra, "malloc"); return AID; } {MAC} { yylval->e = pcap_ether_aton((char *)yytext); if (yylval->e == NULL) bpf_error(yyextra, "malloc"); return EID; } {N} { yylval->i = stoi((char *)yytext); return NUM; } ({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) { yylval->s = sdup(yyextra, (char *)yytext); return HID; } {V6} { #ifdef INET6 struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_flags = AI_NUMERICHOST; if (getaddrinfo(yytext, NULL, &hints, &res)) bpf_error(yyextra, "bogus IPv6 address %s", yytext); else { freeaddrinfo(res); yylval->s = sdup(yyextra, (char *)yytext); return HID6; } #else bpf_error(yyextra, "IPv6 address %s not supported", yytext); #endif /*INET6*/ } {B}:+({B}:+)+ { bpf_error(yyextra, "bogus ethernet address %s", yytext); } icmptype { yylval->i = 0; return NUM; } icmpcode { yylval->i = 1; return NUM; } icmp-echoreply { yylval->i = 0; return NUM; } icmp-unreach { yylval->i = 3; return NUM; } icmp-sourcequench { yylval->i = 4; return NUM; } icmp-redirect { yylval->i = 5; return NUM; } icmp-echo { yylval->i = 8; return NUM; } icmp-routeradvert { yylval->i = 9; return NUM; } icmp-routersolicit { yylval->i = 10; return NUM; } icmp-timxceed { yylval->i = 11; return NUM; } icmp-paramprob { yylval->i = 12; return NUM; } icmp-tstamp { yylval->i = 13; return NUM; } icmp-tstampreply { yylval->i = 14; return NUM; } icmp-ireq { yylval->i = 15; return NUM; } icmp-ireqreply { yylval->i = 16; return NUM; } icmp-maskreq { yylval->i = 17; return NUM; } icmp-maskreply { yylval->i = 18; return NUM; } tcpflags { yylval->i = 13; return NUM; } tcp-fin { yylval->i = 0x01; return NUM; } tcp-syn { yylval->i = 0x02; return NUM; } tcp-rst { yylval->i = 0x04; return NUM; } tcp-push { yylval->i = 0x08; return NUM; } tcp-ack { yylval->i = 0x10; return NUM; } tcp-urg { yylval->i = 0x20; return NUM; } [A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? { yylval->s = sdup(yyextra, (char *)yytext); return ID; } "\\"[^ !()\n\t]+ { yylval->s = sdup(yyextra, (char *)yytext + 1); return ID; } [^ \[\]\t\n\-_.A-Za-z0-9!<>()&|=]+ { bpf_error(yyextra, "illegal token: %s", yytext); } . { bpf_error(yyextra, "illegal char '%c'", *yytext); } %% /* Hex digit to integer. */ static inline int xdtoi(c) register int c; { if (isdigit(c)) return c - '0'; else if (islower(c)) return c - 'a' + 10; else return c - 'A' + 10; } /* * Convert string to integer. Just like atoi(), but checks for * preceding 0x or 0 and uses hex or octal instead of decimal. */ static int stoi(s) char *s; { int base = 10; int n = 0; if (*s == '0') { if (s[1] == 'x' || s[1] == 'X') { s += 2; base = 16; } else { base = 8; s += 1; } } while (*s) n = n * base + xdtoi(*s++); return n; } libpcap-1.8.1/pcap.h0000644000026300017510000000426213003771737012366 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * For backwards compatibility. * * Note to OS vendors: do NOT get rid of this file! Many applications * expect to be able to include , and at least some of them * go through contortions in their configure scripts to try to detect * OSes that have "helpfully" moved pcap.h to without * leaving behind a file. */ #include libpcap-1.8.1/pcap_strerror.3pcap0000644000026300017510000000304713003771737015107 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_STRERROR 3PCAP "3 January 2014" .SH NAME pcap_strerror \- convert an errno value to a string .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B const char *pcap_strerror(int error); .ft .fi .SH DESCRIPTION .B pcap_strerror() is provided in case .BR strerror (3) isn't available. It returns an error message string corresponding to .IR error . .SH SEE ALSO strerror(3) libpcap-1.8.1/pcap_datalink.3pcap.in0000644000026300017510000000460013003771737015415 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_DATALINK 3PCAP "7 April 2014" .SH NAME pcap_datalink \- get the link-layer header type .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_datalink(pcap_t *p); .ft .fi .SH DESCRIPTION .B pcap_datalink() returns the link-layer header type for the live capture or ``savefile'' specified by .IR p . .PP It must not be called on a pcap descriptor created by .B pcap_create() that has not yet been activated by .BR pcap_activate() . .PP .I http://www.tcpdump.org/linktypes.html lists the values .B pcap_datalink() can return and describes the packet formats that correspond to those values. .PP Do .B NOT assume that the packets for a given capture or ``savefile`` will have any given link-layer header type, such as .B DLT_EN10MB for Ethernet. For example, the "any" device on Linux will have a link-layer header type of .B DLT_LINUX_SLL even if all devices on the system at the time the "any" device is opened have some other data link type, such as .B DLT_EN10MB for Ethernet. .SH RETURN VALUE .B pcap_datalink() returns the link-layer header type on success and .B PCAP_ERROR_NOT_ACTIVATED if called on a capture handle that has been created but not activated. .SH SEE ALSO pcap(3PCAP), pcap-linktype(@MAN_MISC_INFO@) libpcap-1.8.1/pcap_set_timeout.3pcap0000644000026300017510000000377413003771737015575 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_SET_TIMEOUT 3PCAP "1 December 2015" .SH NAME pcap_set_timeout \- set the read timeout for a not-yet-activated capture handle .SH SYNOPSIS .nf .ft B #include .LP .ft B int pcap_set_timeout(pcap_t *p, int to_ms); .ft .fi .SH DESCRIPTION .B pcap_set_timeout() sets the read timeout that will be used on a capture handle when the handle is activated to .IR to_ms , which is in units of milliseconds. .LP The behavior, if the timeout isn't specified, is undefined. We recommend always setting the timeout to a non-zero value unless immediate mode is set, in which case the timeout has no effect. .SH RETURN VALUE .B pcap_set_timeout() returns 0 on success or .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), pcap_set_immediate_mode(3PCAP) libpcap-1.8.1/README.linux0000644000026300017510000001160513003771737013307 0ustar mcrmcrIn order for libpcap to be able to capture packets on a Linux system, the "packet" protocol must be supported by your kernel. If it is not, you may get error messages such as modprobe: can't locate module net-pf-17 in "/var/adm/messages", or may get messages such as socket: Address family not supported by protocol from applications using libpcap. You must configure the kernel with the CONFIG_PACKET option for this protocol; the following note is from the Linux "Configure.help" file for the 2.0[.x] kernel: Packet socket CONFIG_PACKET The Packet protocol is used by applications which communicate directly with network devices without an intermediate network protocol implemented in the kernel, e.g. tcpdump. If you want them to work, choose Y. This driver is also available as a module called af_packet.o ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt; if you use modprobe or kmod, you may also want to add "alias net-pf-17 af_packet" to /etc/modules.conf. and the note for the 2.2[.x] kernel says: Packet socket CONFIG_PACKET The Packet protocol is used by applications which communicate directly with network devices without an intermediate network protocol implemented in the kernel, e.g. tcpdump. If you want them to work, choose Y. This driver is also available as a module called af_packet.o ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. You will need to add 'alias net-pf-17 af_packet' to your /etc/conf.modules file for the module version to function automatically. If unsure, say Y. In addition, there is an option that, in 2.2 and later kernels, will allow packet capture filters specified to programs such as tcpdump to be executed in the kernel, so that packets that don't pass the filter won't be copied from the kernel to the program, rather than having all packets copied to the program and libpcap doing the filtering in user mode. Copying packets from the kernel to the program consumes a significant amount of CPU, so filtering in the kernel can reduce the overhead of capturing packets if a filter has been specified that discards a significant number of packets. (If no filter is specified, it makes no difference whether the filtering isn't performed in the kernel or isn't performed in user mode. :-)) The option for this is the CONFIG_FILTER option; the "Configure.help" file says: Socket filtering CONFIG_FILTER The Linux Socket Filter is derived from the Berkeley Packet Filter. If you say Y here, user-space programs can attach a filter to any socket and thereby tell the kernel that it should allow or disallow certain types of data to get through the socket. Linux Socket Filtering works on all socket types except TCP for now. See the text file linux/Documentation/networking/filter.txt for more information. If unsure, say N. Note that, by default, libpcap will, if libnl is present, build with it; it uses libnl to support monitor mode on mac80211 devices. There is a configuration option to disable building with libnl, but, if that option is chosen, the monitor-mode APIs (as used by tcpdump's "-I" flag, and as will probably be used by other applications in the future) won't work properly on mac80211 devices. Linux's run-time linker allows shared libraries to be linked with other shared libraries, which means that if an older version of a shared library doesn't require routines from some other shared library, and a later version of the shared library does require those routines, the later version of the shared library can be linked with that other shared library and, if it's otherwise binary-compatible with the older version, can replace that older version without breaking applications built with the older version, and without breaking configure scripts or the build procedure for applications whose configure script doesn't use the pcap-config script if they build with the shared library. (The build procedure for applications whose configure scripts use the pcap-config script if present will not break even if they build with the static library.) Statistics: Statistics reported by pcap are platform specific. The statistics reported by pcap_stats on Linux are as follows: 2.2.x ===== ps_recv Number of packets that were accepted by the pcap filter ps_drop Always 0, this statistic is not gatherd on this platform 2.4.x ===== ps_recv Number of packets that were accepted by the pcap filter ps_drop Number of packets that had passed filtering but were not passed on to pcap due to things like buffer shortage, etc. This is useful because these are packets you are interested in but won't be reported by, for example, tcpdump output. libpcap-1.8.1/pcap-namedb.h0000644000026300017510000000375013003771737013613 0ustar mcrmcr/* * Copyright (c) 1994, 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * For backwards compatibility. * * Note to OS vendors: do NOT get rid of this file! Some applications * might expect to be able to include . */ #include libpcap-1.8.1/install-sh0000755000026300017510000001271213003771737013275 0ustar mcrmcr#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 libpcap-1.8.1/pcap-bt-monitor-linux.c0000644000026300017510000001603513003771737015607 0ustar mcrmcr/* * Copyright (c) 2014 Michal Labedzki for Tieto Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "pcap/bluetooth.h" #include "pcap-int.h" #include "pcap-bt-monitor-linux.h" #define BT_CONTROL_SIZE 32 #define INTERFACE_NAME "bluetooth-monitor" /* * Fields and alignment must match the declaration in the Linux kernel 3.4+. * See struct hci_mon_hdr in include/net/bluetooth/hci_mon.h. */ struct hci_mon_hdr { uint16_t opcode; uint16_t index; uint16_t len; } __attribute__((packed)); int bt_monitor_findalldevs(pcap_if_t **alldevsp, char *err_str) { int ret = 0; if (pcap_add_if(alldevsp, INTERFACE_NAME, 0, "Bluetooth Linux Monitor", err_str) < 0) { ret = -1; } return ret; } static int bt_monitor_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user) { struct cmsghdr *cmsg; struct msghdr msg; struct iovec iv[2]; ssize_t ret; struct pcap_pkthdr pkth; pcap_bluetooth_linux_monitor_header *bthdr; u_char *pktd; struct hci_mon_hdr hdr; pktd = (u_char *)handle->buffer + BT_CONTROL_SIZE; bthdr = (pcap_bluetooth_linux_monitor_header*)(void *)pktd; iv[0].iov_base = &hdr; iv[0].iov_len = sizeof(hdr); iv[1].iov_base = pktd + sizeof(pcap_bluetooth_linux_monitor_header); iv[1].iov_len = handle->snapshot; memset(&pkth.ts, 0, sizeof(pkth.ts)); memset(&msg, 0, sizeof(msg)); msg.msg_iov = iv; msg.msg_iovlen = 2; msg.msg_control = handle->buffer; msg.msg_controllen = BT_CONTROL_SIZE; do { ret = recvmsg(handle->fd, &msg, 0); if (handle->break_loop) { handle->break_loop = 0; return -2; } } while ((ret == -1) && (errno == EINTR)); if (ret < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet: %s", strerror(errno)); return -1; } pkth.caplen = ret - sizeof(hdr) + sizeof(pcap_bluetooth_linux_monitor_header); pkth.len = pkth.caplen; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level != SOL_SOCKET) continue; if (cmsg->cmsg_type == SCM_TIMESTAMP) { memcpy(&pkth.ts, CMSG_DATA(cmsg), sizeof(pkth.ts)); } } bthdr->adapter_id = htons(hdr.index); bthdr->opcode = htons(hdr.opcode); if (handle->fcode.bf_insns == NULL || bpf_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) { callback(user, &pkth, pktd); return 1; } return 0; /* didn't pass filter */ } static int bt_monitor_inject(pcap_t *handle, const void *buf _U_, size_t size _U_) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported yet"); return -1; } static int bt_monitor_setdirection(pcap_t *p, pcap_direction_t d) { p->direction = d; return 0; } static int bt_monitor_stats(pcap_t *handle _U_, struct pcap_stat *stats) { stats->ps_recv = 0; stats->ps_drop = 0; stats->ps_ifdrop = 0; return 0; } static int bt_monitor_activate(pcap_t* handle) { struct sockaddr_hci addr; int err = PCAP_ERROR; int opt; if (handle->opt.rfmon) { /* monitor mode doesn't apply here */ return PCAP_ERROR_RFMON_NOTSUP; } handle->bufsize = BT_CONTROL_SIZE + sizeof(pcap_bluetooth_linux_monitor_header) + handle->snapshot; handle->linktype = DLT_BLUETOOTH_LINUX_MONITOR; handle->read_op = bt_monitor_read; handle->inject_op = bt_monitor_inject; handle->setfilter_op = install_bpf_program; /* no kernel filtering */ handle->setdirection_op = bt_monitor_setdirection; handle->set_datalink_op = NULL; /* can't change data link type */ handle->getnonblock_op = pcap_getnonblock_fd; handle->setnonblock_op = pcap_setnonblock_fd; handle->stats_op = bt_monitor_stats; handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (handle->fd < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't create raw socket: %s", strerror(errno)); return PCAP_ERROR; } handle->buffer = malloc(handle->bufsize); if (!handle->buffer) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", pcap_strerror(errno)); goto close_fail; } /* Bind socket to the HCI device */ addr.hci_family = AF_BLUETOOTH; addr.hci_dev = HCI_DEV_NONE; addr.hci_channel = HCI_CHANNEL_MONITOR; if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't attach to interface: %s", strerror(errno)); goto close_fail; } opt = 1; if (setsockopt(handle->fd, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt)) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't enable time stamp: %s", strerror(errno)); goto close_fail; } handle->selectable_fd = handle->fd; return 0; close_fail: pcap_cleanup_live_common(handle); return err; } pcap_t * bt_monitor_create(const char *device, char *ebuf, int *is_ours) { pcap_t *p; const char *cp; cp = strrchr(device, '/'); if (cp == NULL) cp = device; if (strcmp(cp, INTERFACE_NAME) != 0) { *is_ours = 0; return NULL; } *is_ours = 1; p = pcap_create_common(ebuf, 0); if (p == NULL) return NULL; p->activate_op = bt_monitor_activate; return p; } libpcap-1.8.1/TODO0000644000026300017510000000301513003771737011755 0ustar mcrmcr TODO list for libpcap ======================= Important stuff (to be done before the next release) --------------- General - configure should not be in Git. Most open source projects have an autogen.sh script to run autoconf etc. after checkout. I think we should stick to the standard. - The source files should be better documented. There is no official design guideline for what is done where. There should be a common coding style (okay, you can guess that by looking at the code) and a guide for what needs to be documented. Less urgent items ----------------- - Better documentation and cleanup of the interface. I am seeing a few problems at the first glance which needs fixing: + pcap_lookupnet makes little to no sense with protocols != IPv4 + not very well suited for interactive programs (think ethereal). There should be a way for the application to get a file descriptor which it has to monitor and a callback in pcap which has to be called on activity (XXX - "pcap_fileno()" handles the first part, although "select()" and "poll()" don't work on BPF devices on most BSDs, and you can call "pcap_dispatch()" as the dispatch routine after putting the descriptor into non-blocking mode) + too many functions. There are a lot of functions for everything which violates the KISS principle. Why do we need pcap_strerror, pcap_perror and pcap_geterr? + the manpage has a brief description of each function but where is the big picture? Seems like you need to buy UNP for that... libpcap-1.8.1/ChmodBPF/0000755000026300017510000000000013003775545012651 5ustar mcrmcrlibpcap-1.8.1/ChmodBPF/ChmodBPF0000755000026300017510000000160413003771737014161 0ustar mcrmcr#! /bin/sh . /etc/rc.common StartService () { # # Unfortunately, Mac OS X's devfs is based on the old FreeBSD # one, not the current one, so there's no way to configure it # to create BPF devices with particular owners or groups. # This startup item will make it owned by the admin group, # with permissions rw-rw----, so that anybody in the admin # group can use programs that capture or send raw packets. # # Change this as appropriate for your site, e.g. to make # it owned by a particular user without changing the permissions, # so only that user and the super-user can capture or send raw # packets, or give it the permissions rw-r-----, so that # only the super-user can send raw packets but anybody in the # admin group can capture packets. # chgrp admin /dev/bpf* chmod g+rw /dev/bpf* } StopService () { return 0; } RestartService () { StartService; } RunService "$1" libpcap-1.8.1/ChmodBPF/StartupParameters.plist0000644000026300017510000000012413003771737017410 0ustar mcrmcr{ Description = "Change BPF permissions"; Provides = ("ChmodBPF"); } libpcap-1.8.1/README.septel0000644000026300017510000000377413003771737013454 0ustar mcrmcrThe following instructions apply if you have a Linux platform and want libpcap to support the Septel range of passive network monitoring cards from Intel (http://www.intel.com) 1) Install and build the Septel software distribution by following the instructions supplied with that package. 2) Configure libcap. To allow the 'configure' script to locate the Septel software distribution use the '--with-septel' option: ./configure --with-septel=DIR where DIR is the root of the Septel software distribution, for example /var/src/septel. By default (if you write only ./configure --with-septel) it takes ./../septel as argument for DIR. If the Septel software is correctly detected 'configure' will report: checking whether we have Septel API... yes If 'configure' reports that there is no Septel API, the directory may have been incorrectly specified or the Septel software was not built before configuring libpcap. See also the libpcap INSTALL.txt file for further libpcap configuration options. Building libpcap at this stage will include support for both the native packet capture stream and for capturing from Septel cards. To build libpcap with only Septel support specify the capture type as 'septel' when configuring libpcap: ./configure --with-septel=DIR --with-pcap=septel Applications built with libpcap configured in this way will only detect Septel cards and will not capture from the native OS packet stream. Note: As mentioned in pcap-septel.c we should first edit the system.txt file to change the user part example (UPE) module id to 0xdd instead of 0x2d for technical reason. So this change in system.txt is crutial and things will go wrong if it's not done. System.txt along with config.txt are configuration files that are edited by the user before running the gctload program that uses these files for initialising modules and configuring parameters. ---------------------------------------------------------------------- for more information please contact me : gil_hoyek@hotmail.com libpcap-1.8.1/pcap-dos.c0000644000026300017510000010610313003771737013141 0ustar mcrmcr/* * This file is part of DOS-libpcap * Ported to DOS/DOSX by G. Vanem * * pcap-dos.c: Interface to PKTDRVR, NDIS2 and 32-bit pmode * network drivers. */ #include #include #include #include #include #include #include #if defined(USE_32BIT_DRIVERS) #include "msdos/pm_drvr/pmdrvr.h" #include "msdos/pm_drvr/pci.h" #include "msdos/pm_drvr/bios32.h" #include "msdos/pm_drvr/module.h" #include "msdos/pm_drvr/3c501.h" #include "msdos/pm_drvr/3c503.h" #include "msdos/pm_drvr/3c509.h" #include "msdos/pm_drvr/3c59x.h" #include "msdos/pm_drvr/3c515.h" #include "msdos/pm_drvr/3c90x.h" #include "msdos/pm_drvr/3c575_cb.h" #include "msdos/pm_drvr/ne.h" #include "msdos/pm_drvr/wd.h" #include "msdos/pm_drvr/accton.h" #include "msdos/pm_drvr/cs89x0.h" #include "msdos/pm_drvr/rtl8139.h" #include "msdos/pm_drvr/ne2k-pci.h" #endif #include "pcap.h" #include "pcap-dos.h" #include "pcap-int.h" #include "msdos/pktdrvr.h" #ifdef USE_NDIS2 #include "msdos/ndis2.h" #endif #include #include #include #include #include #include #if defined(USE_32BIT_DRIVERS) #define FLUSHK() do { _printk_safe = 1; _printk_flush(); } while (0) #define NDIS_NEXT_DEV &rtl8139_dev static char *rx_pool = NULL; static void init_32bit (void); static int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool); static int pktq_check (struct rx_ringbuf *q); static int pktq_inc_out (struct rx_ringbuf *q); static int pktq_in_index (struct rx_ringbuf *q) LOCKED_FUNC; static void pktq_clear (struct rx_ringbuf *q) LOCKED_FUNC; static struct rx_elem *pktq_in_elem (struct rx_ringbuf *q) LOCKED_FUNC; static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q); #else #define FLUSHK() ((void)0) #define NDIS_NEXT_DEV NULL #endif /* * Internal variables/functions in Watt-32 */ extern WORD _pktdevclass; extern BOOL _eth_is_init; extern int _w32_dynamic_host; extern int _watt_do_exit; extern int _watt_is_init; extern int _w32__bootp_on, _w32__dhcp_on, _w32__rarp_on, _w32__do_mask_req; extern void (*_w32_usr_post_init) (void); extern void (*_w32_print_hook)(); extern void dbug_write (const char *); /* Watt-32 lib, pcdbug.c */ extern int pkt_get_mtu (void); static int ref_count = 0; static u_long mac_count = 0; static u_long filter_count = 0; static volatile BOOL exc_occured = 0; static struct device *handle_to_device [20]; static int pcap_activate_dos (pcap_t *p); static int pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, u_char *data); static void pcap_cleanup_dos (pcap_t *p); static int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps); static int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len); static int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp); static int ndis_probe (struct device *dev); static int pkt_probe (struct device *dev); static void close_driver (void); static int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf); static int first_init (const char *name, char *ebuf, int promisc); static void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap, const u_char *buf); /* * These are the device we always support */ static struct device ndis_dev = { "ndis", "NDIS2 LanManager", 0, 0,0,0,0,0,0, NDIS_NEXT_DEV, /* NULL or a 32-bit device */ ndis_probe }; static struct device pkt_dev = { "pkt", "Packet-Driver", 0, 0,0,0,0,0,0, &ndis_dev, pkt_probe }; static struct device *get_device (int fd) { if (fd <= 0 || fd >= sizeof(handle_to_device)/sizeof(handle_to_device[0])) return (NULL); return handle_to_device [fd-1]; } /* * Private data for capturing on MS-DOS. */ struct pcap_dos { void (*wait_proc)(void); /* call proc while waiting */ struct pcap_stat stat; }; pcap_t *pcap_create_interface (const char *device _U_, char *ebuf) { pcap_t *p; p = pcap_create_common(ebuf, sizeof (struct pcap_dos)); if (p == NULL) return (NULL); p->activate_op = pcap_activate_dos; return (p); } /* * Open MAC-driver with name 'device_name' for live capture of * network packets. */ static int pcap_activate_dos (pcap_t *pcap) { if (pcap->opt.rfmon) { /* * No monitor mode on DOS. */ return (PCAP_ERROR_RFMON_NOTSUP); } if (pcap->snapshot < ETH_MIN+8) pcap->snapshot = ETH_MIN+8; if (pcap->snapshot > ETH_MAX) /* silently accept and truncate large MTUs */ pcap->snapshot = ETH_MAX; pcap->linktype = DLT_EN10MB; /* !! */ pcap->cleanup_op = pcap_cleanup_dos; pcap->read_op = pcap_read_dos; pcap->stats_op = pcap_stats_dos; pcap->inject_op = pcap_sendpacket_dos; pcap->setfilter_op = pcap_setfilter_dos; pcap->setdirection_op = NULL; /* Not implemented.*/ pcap->fd = ++ref_count; pcap->bufsize = ETH_MAX+100; /* add some margin */ pcap->buffer = calloc (pcap->bufsize, 1); if (pcap->fd == 1) /* first time we're called */ { if (!init_watt32(pcap, pcap->opt.device, pcap->errbuf) || !first_init(pcap->opt.device, pcap->errbuf, pcap->opt.promisc)) { return (PCAP_ERROR); } atexit (close_driver); } else if (stricmp(active_dev->name,pcap->opt.device)) { pcap_snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE, "Cannot use different devices simultaneously " "(`%s' vs. `%s')", active_dev->name, pcap->opt.device); return (PCAP_ERROR); } handle_to_device [pcap->fd-1] = active_dev; return (0); } /* * Poll the receiver queue and call the pcap callback-handler * with the packet. */ static int pcap_read_one (pcap_t *p, pcap_handler callback, u_char *data) { struct pcap_dos *pd = p->priv; struct pcap_pkthdr pcap; struct timeval now, expiry = { 0,0 }; int rx_len = 0; if (p->opt.timeout > 0) { gettimeofday2 (&now, NULL); expiry.tv_usec = now.tv_usec + 1000UL * p->opt.timeout; expiry.tv_sec = now.tv_sec; while (expiry.tv_usec >= 1000000L) { expiry.tv_usec -= 1000000L; expiry.tv_sec++; } } while (!exc_occured) { volatile struct device *dev; /* might be reset by sig_handler */ dev = get_device (p->fd); if (!dev) break; PCAP_ASSERT (dev->copy_rx_buf || dev->peek_rx_buf); FLUSHK(); /* If driver has a zero-copy receive facility, peek at the queue, * filter it, do the callback and release the buffer. */ if (dev->peek_rx_buf) { PCAP_ASSERT (dev->release_rx_buf); rx_len = (*dev->peek_rx_buf) (&p->buffer); } else { rx_len = (*dev->copy_rx_buf) (p->buffer, p->snapshot); } if (rx_len > 0) /* got a packet */ { mac_count++; FLUSHK(); pcap.caplen = min (rx_len, p->snapshot); pcap.len = rx_len; if (callback && (!p->fcode.bf_insns || bpf_filter(p->fcode.bf_insns, p->buffer, pcap.len, pcap.caplen))) { filter_count++; /* Fix-me!! Should be time of arrival. Not time of * capture. */ gettimeofday2 (&pcap.ts, NULL); (*callback) (data, &pcap, p->buffer); } if (dev->release_rx_buf) (*dev->release_rx_buf) (p->buffer); if (pcap_pkt_debug > 0) { if (callback == watt32_recv_hook) dbug_write ("pcap_recv_hook\n"); else dbug_write ("pcap_read_op\n"); } FLUSHK(); return (1); } /* Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that it * has, and return -2 to indicate that we were * told to break out of the loop. */ p->break_loop = 0; return (-2); } /* If not to wait for a packet or pcap_cleanup_dos() called from * e.g. SIGINT handler, exit loop now. */ if (p->opt.timeout <= 0 || (volatile int)p->fd <= 0) break; gettimeofday2 (&now, NULL); if (timercmp(&now, &expiry, >)) break; #ifndef DJGPP kbhit(); /* a real CPU hog */ #endif if (pd->wait_proc) (*pd->wait_proc)(); /* call yield func */ } if (rx_len < 0) /* receive error */ { pd->stat.ps_drop++; #ifdef USE_32BIT_DRIVERS if (pcap_pkt_debug > 1) printk ("pkt-err %s\n", pktInfo.error); #endif return (-1); } return (0); } static int pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, u_char *data) { int rc, num = 0; while (num <= cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) { if (p->fd <= 0) return (-1); rc = pcap_read_one (p, callback, data); if (rc > 0) num++; if (rc < 0) break; _w32_os_yield(); /* allow SIGINT generation, yield to Win95/NT */ } return (num); } /* * Return network statistics */ static int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps) { struct net_device_stats *stats; struct pcap_dos *pd; struct device *dev = p ? get_device(p->fd) : NULL; if (!dev) { strcpy (p->errbuf, "illegal pcap handle"); return (-1); } if (!dev->get_stats || (stats = (*dev->get_stats)(dev)) == NULL) { strcpy (p->errbuf, "device statistics not available"); return (-1); } FLUSHK(); pd = p->priv; pd->stat.ps_recv = stats->rx_packets; pd->stat.ps_drop += stats->rx_missed_errors; pd->stat.ps_ifdrop = stats->rx_dropped + /* queue full */ stats->rx_errors; /* HW errors */ if (ps) *ps = pd->stat; return (0); } /* * Return detailed network/device statistics. * May be called after 'dev->close' is called. */ int pcap_stats_ex (pcap_t *p, struct pcap_stat_ex *se) { struct device *dev = p ? get_device (p->fd) : NULL; if (!dev || !dev->get_stats) { strlcpy (p->errbuf, "detailed device statistics not available", PCAP_ERRBUF_SIZE); return (-1); } if (!strnicmp(dev->name,"pkt",3)) { strlcpy (p->errbuf, "pktdrvr doesn't have detailed statistics", PCAP_ERRBUF_SIZE); return (-1); } memcpy (se, (*dev->get_stats)(dev), sizeof(*se)); return (0); } /* * Simply store the filter-code for the pcap_read_dos() callback * Some day the filter-code could be handed down to the active * device (pkt_rx1.s or 32-bit device interrupt handler). */ static int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp) { if (!p) return (-1); p->fcode = *fp; return (0); } /* * Return # of packets received in pcap_read_dos() */ u_long pcap_mac_packets (void) { return (mac_count); } /* * Return # of packets passed through filter in pcap_read_dos() */ u_long pcap_filter_packets (void) { return (filter_count); } /* * Close pcap device. Not called for offline captures. */ static void pcap_cleanup_dos (pcap_t *p) { struct pcap_dos *pd; if (!exc_occured) { pd = p->priv; if (pcap_stats(p,NULL) < 0) pd->stat.ps_drop = 0; if (!get_device(p->fd)) return; handle_to_device [p->fd-1] = NULL; p->fd = 0; if (ref_count > 0) ref_count--; if (ref_count > 0) return; } close_driver(); } /* * Return the name of the 1st network interface, * or NULL if none can be found. */ char *pcap_lookupdev (char *ebuf) { struct device *dev; #ifdef USE_32BIT_DRIVERS init_32bit(); #endif for (dev = (struct device*)dev_base; dev; dev = dev->next) { PCAP_ASSERT (dev->probe); if ((*dev->probe)(dev)) { FLUSHK(); probed_dev = (struct device*) dev; /* remember last probed device */ return (char*) dev->name; } } if (ebuf) strcpy (ebuf, "No driver found"); return (NULL); } /* * Gets localnet & netmask from Watt-32. */ int pcap_lookupnet (const char *device, bpf_u_int32 *localnet, bpf_u_int32 *netmask, char *errbuf) { DWORD mask, net; if (!_watt_is_init) { strcpy (errbuf, "pcap_open_offline() or pcap_activate() must be " "called first"); return (-1); } mask = _w32_sin_mask; net = my_ip_addr & mask; if (net == 0) { if (IN_CLASSA(*netmask)) net = IN_CLASSA_NET; else if (IN_CLASSB(*netmask)) net = IN_CLASSB_NET; else if (IN_CLASSC(*netmask)) net = IN_CLASSC_NET; else { pcap_snprintf (errbuf, PCAP_ERRBUF_SIZE, "inet class for 0x%lx unknown", mask); return (-1); } } *localnet = htonl (net); *netmask = htonl (mask); ARGSUSED (device); return (0); } /* * Get a list of all interfaces that are present and that we probe okay. * Returns -1 on error, 0 otherwise. * The list, as returned through "alldevsp", may be NULL if no interfaces * were up and could be opened. */ int pcap_platform_finddevs (pcap_if_t **alldevsp, char *errbuf) { struct device *dev; struct sockaddr_in sa_ll_1, sa_ll_2; struct sockaddr *addr, *netmask, *broadaddr, *dstaddr; pcap_if_t *devlist = NULL; int ret = 0; size_t addr_size = sizeof(*addr); for (dev = (struct device*)dev_base; dev; dev = dev->next) { PCAP_ASSERT (dev->probe); if (!(*dev->probe)(dev)) continue; PCAP_ASSERT (dev->close); /* set by probe routine */ FLUSHK(); (*dev->close) (dev); memset (&sa_ll_1, 0, sizeof(sa_ll_1)); memset (&sa_ll_2, 0, sizeof(sa_ll_2)); sa_ll_1.sin_family = AF_INET; sa_ll_2.sin_family = AF_INET; addr = (struct sockaddr*) &sa_ll_1; netmask = (struct sockaddr*) &sa_ll_1; dstaddr = (struct sockaddr*) &sa_ll_1; broadaddr = (struct sockaddr*) &sa_ll_2; memset (&sa_ll_2.sin_addr, 0xFF, sizeof(sa_ll_2.sin_addr)); if (pcap_add_if(&devlist, dev->name, dev->flags, dev->long_name, errbuf) < 0) { ret = -1; break; } #if 0 /* Pkt drivers should have no addresses */ if (add_addr_to_iflist(&devlist, dev->name, dev->flags, addr, addr_size, netmask, addr_size, broadaddr, addr_size, dstaddr, addr_size, errbuf) < 0) { ret = -1; break; } #endif } if (devlist && ret < 0) { pcap_freealldevs (devlist); devlist = NULL; } else if (!devlist) strcpy (errbuf, "No drivers found"); *alldevsp = devlist; return (ret); } /* * pcap_assert() is mainly used for debugging */ void pcap_assert (const char *what, const char *file, unsigned line) { FLUSHK(); fprintf (stderr, "%s (%u): Assertion \"%s\" failed\n", file, line, what); close_driver(); _exit (-1); } /* * For pcap_offline_read(): wait and yield between printing packets * to simulate the pace packets where actually recorded. */ void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait) { if (p) { struct pcap_dos *pd = p->priv; pd->wait_proc = yield; p->opt.timeout = wait; } } /* * Initialise a named network device. */ static struct device * open_driver (const char *dev_name, char *ebuf, int promisc) { struct device *dev; for (dev = (struct device*)dev_base; dev; dev = dev->next) { PCAP_ASSERT (dev->name); if (strcmp (dev_name,dev->name)) continue; if (!probed_dev) /* user didn't call pcap_lookupdev() first */ { PCAP_ASSERT (dev->probe); if (!(*dev->probe)(dev)) /* call the xx_probe() function */ { pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to detect device `%s'", dev_name); return (NULL); } probed_dev = dev; /* device is probed okay and may be used */ } else if (dev != probed_dev) { goto not_probed; } FLUSHK(); /* Select what traffic to receive */ if (promisc) dev->flags |= (IFF_ALLMULTI | IFF_PROMISC); else dev->flags &= ~(IFF_ALLMULTI | IFF_PROMISC); PCAP_ASSERT (dev->open); if (!(*dev->open)(dev)) { pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to activate device `%s'", dev_name); if (pktInfo.error && !strncmp(dev->name,"pkt",3)) { strcat (ebuf, ": "); strcat (ebuf, pktInfo.error); } return (NULL); } /* Some devices need this to operate in promiscous mode */ if (promisc && dev->set_multicast_list) (*dev->set_multicast_list) (dev); active_dev = dev; /* remember our active device */ break; } /* 'dev_name' not matched in 'dev_base' list. */ if (!dev) { pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not supported", dev_name); return (NULL); } not_probed: if (!probed_dev) { pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not probed", dev_name); return (NULL); } return (dev); } /* * Deinitialise MAC driver. * Set receive mode back to default mode. */ static void close_driver (void) { /* !!todo: loop over all 'handle_to_device[]' ? */ struct device *dev = active_dev; if (dev && dev->close) { (*dev->close) (dev); FLUSHK(); } active_dev = NULL; #ifdef USE_32BIT_DRIVERS if (rx_pool) { k_free (rx_pool); rx_pool = NULL; } if (dev) pcibios_exit(); #endif } #ifdef __DJGPP__ static void setup_signals (void (*handler)(int)) { signal (SIGSEGV,handler); signal (SIGILL, handler); signal (SIGFPE, handler); } static void exc_handler (int sig) { #ifdef USE_32BIT_DRIVERS if (active_dev->irq > 0) /* excludes IRQ 0 */ { disable_irq (active_dev->irq); irq_eoi_cmd (active_dev->irq); _printk_safe = 1; } #endif switch (sig) { case SIGSEGV: fputs ("Catching SIGSEGV.\n", stderr); break; case SIGILL: fputs ("Catching SIGILL.\n", stderr); break; case SIGFPE: _fpreset(); fputs ("Catching SIGFPE.\n", stderr); break; default: fprintf (stderr, "Catching signal %d.\n", sig); } exc_occured = 1; close_driver(); } #endif /* __DJGPP__ */ /* * Open the pcap device for the first client calling pcap_activate() */ static int first_init (const char *name, char *ebuf, int promisc) { struct device *dev; #ifdef USE_32BIT_DRIVERS rx_pool = k_calloc (RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE); if (!rx_pool) { strcpy (ebuf, "Not enough memory (Rx pool)"); return (0); } #endif #ifdef __DJGPP__ setup_signals (exc_handler); #endif #ifdef USE_32BIT_DRIVERS init_32bit(); #endif dev = open_driver (name, ebuf, promisc); if (!dev) { #ifdef USE_32BIT_DRIVERS k_free (rx_pool); rx_pool = NULL; #endif #ifdef __DJGPP__ setup_signals (SIG_DFL); #endif return (0); } #ifdef USE_32BIT_DRIVERS /* * If driver is NOT a 16-bit "pkt/ndis" driver (having a 'copy_rx_buf' * set in it's probe handler), initialise near-memory ring-buffer for * the 32-bit device. */ if (dev->copy_rx_buf == NULL) { dev->get_rx_buf = get_rxbuf; dev->peek_rx_buf = peek_rxbuf; dev->release_rx_buf = release_rxbuf; pktq_init (&dev->queue, RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE, rx_pool); } #endif return (1); } #ifdef USE_32BIT_DRIVERS static void init_32bit (void) { static int init_pci = 0; if (!_printk_file) _printk_init (64*1024, NULL); /* calls atexit(printk_exit) */ if (!init_pci) (void)pci_init(); /* init BIOS32+PCI interface */ init_pci = 1; } #endif /* * Hook functions for using Watt-32 together with pcap */ static char rxbuf [ETH_MAX+100]; /* rx-buffer with some margin */ static WORD etype; static pcap_t pcap_save; static void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap, const u_char *buf) { /* Fix me: assumes Ethernet II only */ struct ether_header *ep = (struct ether_header*) buf; memcpy (rxbuf, buf, pcap->caplen); etype = ep->ether_type; ARGSUSED (dummy); } #if (WATTCP_VER >= 0x0224) /* * This function is used by Watt-32 to poll for a packet. * i.e. it's set to bypass _eth_arrived() */ static void *pcap_recv_hook (WORD *type) { int len = pcap_read_dos (&pcap_save, 1, watt32_recv_hook, NULL); if (len < 0) return (NULL); *type = etype; return (void*) &rxbuf; } /* * This function is called by Watt-32 (via _eth_xmit_hook). * If dbug_init() was called, we should trace packets sent. */ static int pcap_xmit_hook (const void *buf, unsigned len) { int rc = 0; if (pcap_pkt_debug > 0) dbug_write ("pcap_xmit_hook: "); if (active_dev && active_dev->xmit) if ((*active_dev->xmit) (active_dev, buf, len) > 0) rc = len; if (pcap_pkt_debug > 0) dbug_write (rc ? "ok\n" : "fail\n"); return (rc); } #endif static int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len) { struct device *dev = p ? get_device(p->fd) : NULL; if (!dev || !dev->xmit) return (-1); return (*dev->xmit) (dev, buf, len); } /* * This function is called by Watt-32 in tcp_post_init(). * We should prevent Watt-32 from using BOOTP/DHCP/RARP etc. */ static void (*prev_post_hook) (void); static void pcap_init_hook (void) { _w32__bootp_on = _w32__dhcp_on = _w32__rarp_on = 0; _w32__do_mask_req = 0; _w32_dynamic_host = 0; if (prev_post_hook) (*prev_post_hook)(); } /* * Supress PRINT message from Watt-32's sock_init() */ static void null_print (void) {} /* * To use features of Watt-32 (netdb functions and socket etc.) * we must call sock_init(). But we set various hooks to prevent * using normal PKTDRVR functions in pcpkt.c. This should hopefully * make Watt-32 and pcap co-operate. */ static int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf) { char *env; int rc, MTU, has_ip_addr; int using_pktdrv = 1; /* If user called sock_init() first, we need to reinit in * order to open debug/trace-file properly */ if (_watt_is_init) sock_exit(); env = getenv ("PCAP_TRACE"); if (env && atoi(env) > 0 && pcap_pkt_debug < 0) /* if not already set */ { dbug_init(); pcap_pkt_debug = atoi (env); } _watt_do_exit = 0; /* prevent sock_init() calling exit() */ prev_post_hook = _w32_usr_post_init; _w32_usr_post_init = pcap_init_hook; _w32_print_hook = null_print; if (dev_name && strncmp(dev_name,"pkt",3)) using_pktdrv = FALSE; rc = sock_init(); has_ip_addr = (rc != 8); /* IP-address assignment failed */ /* if pcap is using a 32-bit driver w/o a pktdrvr loaded, we * just pretend Watt-32 is initialised okay. * * !! fix-me: The Watt-32 config isn't done if no pktdrvr * was found. In that case my_ip_addr + sin_mask * have default values. Should be taken from another * ini-file/environment in any case (ref. tcpdump.ini) */ _watt_is_init = 1; if (!using_pktdrv || !has_ip_addr) /* for now .... */ { static const char myip[] = "192.168.0.1"; static const char mask[] = "255.255.255.0"; printf ("Just guessing, using IP %s and netmask %s\n", myip, mask); my_ip_addr = aton (myip); _w32_sin_mask = aton (mask); } else if (rc && using_pktdrv) { pcap_snprintf (err_buf, PCAP_ERRBUF_SIZE, "sock_init() failed, code %d", rc); return (0); } /* Set recv-hook for peeking in _eth_arrived(). */ #if (WATTCP_VER >= 0x0224) _eth_recv_hook = pcap_recv_hook; _eth_xmit_hook = pcap_xmit_hook; #endif /* Free the pkt-drvr handle allocated in pkt_init(). * The above hooks should thus use the handle reopened in open_driver() */ if (using_pktdrv) { _eth_release(); /* _eth_is_init = 1; */ /* hack to get Rx/Tx-hooks in Watt-32 working */ } memcpy (&pcap_save, pcap, sizeof(pcap_save)); MTU = pkt_get_mtu(); pcap_save.fcode.bf_insns = NULL; pcap_save.linktype = _eth_get_hwtype (NULL, NULL); pcap_save.snapshot = MTU > 0 ? MTU : ETH_MAX; /* assume 1514 */ #if 1 /* prevent use of resolve() and resolve_ip() */ last_nameserver = 0; #endif return (1); } int EISA_bus = 0; /* Where is natural place for this? */ /* * Application config hooks to set various driver parameters. */ static const struct config_table debug_tab[] = { { "PKT.DEBUG", ARG_ATOI, &pcap_pkt_debug }, { "PKT.VECTOR", ARG_ATOX_W, NULL }, { "NDIS.DEBUG", ARG_ATOI, NULL }, #ifdef USE_32BIT_DRIVERS { "3C503.DEBUG", ARG_ATOI, &ei_debug }, { "3C503.IO_BASE", ARG_ATOX_W, &el2_dev.base_addr }, { "3C503.MEMORY", ARG_ATOX_W, &el2_dev.mem_start }, { "3C503.IRQ", ARG_ATOI, &el2_dev.irq }, { "3C505.DEBUG", ARG_ATOI, NULL }, { "3C505.BASE", ARG_ATOX_W, NULL }, { "3C507.DEBUG", ARG_ATOI, NULL }, { "3C509.DEBUG", ARG_ATOI, &el3_debug }, { "3C509.ILOOP", ARG_ATOI, &el3_max_loop }, { "3C529.DEBUG", ARG_ATOI, NULL }, { "3C575.DEBUG", ARG_ATOI, &debug_3c575 }, { "3C59X.DEBUG", ARG_ATOI, &vortex_debug }, { "3C59X.IFACE0", ARG_ATOI, &vortex_options[0] }, { "3C59X.IFACE1", ARG_ATOI, &vortex_options[1] }, { "3C59X.IFACE2", ARG_ATOI, &vortex_options[2] }, { "3C59X.IFACE3", ARG_ATOI, &vortex_options[3] }, { "3C90X.DEBUG", ARG_ATOX_W, &tc90xbc_debug }, { "ACCT.DEBUG", ARG_ATOI, ðpk_debug }, { "CS89.DEBUG", ARG_ATOI, &cs89_debug }, { "RTL8139.DEBUG", ARG_ATOI, &rtl8139_debug }, /* { "RTL8139.FDUPLEX", ARG_ATOI, &rtl8139_options }, */ { "SMC.DEBUG", ARG_ATOI, &ei_debug }, /* { "E100.DEBUG", ARG_ATOI, &e100_debug }, */ { "PCI.DEBUG", ARG_ATOI, &pci_debug }, { "BIOS32.DEBUG", ARG_ATOI, &bios32_debug }, { "IRQ.DEBUG", ARG_ATOI, &irq_debug }, { "TIMER.IRQ", ARG_ATOI, &timer_irq }, #endif { NULL } }; /* * pcap_config_hook() is an extension to application's config * handling. Uses Watt-32's config-table function. */ int pcap_config_hook (const char *keyword, const char *value) { return parse_config_table (debug_tab, NULL, keyword, value); } /* * Linked list of supported devices */ struct device *active_dev = NULL; /* the device we have opened */ struct device *probed_dev = NULL; /* the device we have probed */ const struct device *dev_base = &pkt_dev; /* list of network devices */ /* * PKTDRVR device functions */ int pcap_pkt_debug = -1; static void pkt_close (struct device *dev) { BOOL okay = PktExitDriver(); if (pcap_pkt_debug > 1) fprintf (stderr, "pkt_close(): %d\n", okay); if (dev->priv) free (dev->priv); dev->priv = NULL; } static int pkt_open (struct device *dev) { PKT_RX_MODE mode; if (dev->flags & IFF_PROMISC) mode = PDRX_ALL_PACKETS; else mode = PDRX_BROADCAST; if (!PktInitDriver(mode)) return (0); PktResetStatistics (pktInfo.handle); PktQueueBusy (FALSE); return (1); } static int pkt_xmit (struct device *dev, const void *buf, int len) { struct net_device_stats *stats = (struct net_device_stats*) dev->priv; if (pcap_pkt_debug > 0) dbug_write ("pcap_xmit\n"); if (!PktTransmit(buf,len)) { stats->tx_errors++; return (0); } return (len); } static void *pkt_stats (struct device *dev) { struct net_device_stats *stats = (struct net_device_stats*) dev->priv; if (!stats || !PktSessStatistics(pktInfo.handle)) return (NULL); stats->rx_packets = pktStat.inPackets; stats->rx_errors = pktStat.lost; stats->rx_missed_errors = PktRxDropped(); return (stats); } static int pkt_probe (struct device *dev) { if (!PktSearchDriver()) return (0); dev->open = pkt_open; dev->xmit = pkt_xmit; dev->close = pkt_close; dev->get_stats = pkt_stats; dev->copy_rx_buf = PktReceive; /* farmem peek and copy routine */ dev->get_rx_buf = NULL; dev->peek_rx_buf = NULL; dev->release_rx_buf = NULL; dev->priv = calloc (sizeof(struct net_device_stats), 1); if (!dev->priv) return (0); return (1); } /* * NDIS device functions */ static void ndis_close (struct device *dev) { #ifdef USE_NDIS2 NdisShutdown(); #endif ARGSUSED (dev); } static int ndis_open (struct device *dev) { int promis = (dev->flags & IFF_PROMISC); #ifdef USE_NDIS2 if (!NdisInit(promis)) return (0); return (1); #else ARGSUSED (promis); return (0); #endif } static void *ndis_stats (struct device *dev) { static struct net_device_stats stats; /* to-do */ ARGSUSED (dev); return (&stats); } static int ndis_probe (struct device *dev) { #ifdef USE_NDIS2 if (!NdisOpen()) return (0); #endif dev->open = ndis_open; dev->xmit = NULL; dev->close = ndis_close; dev->get_stats = ndis_stats; dev->copy_rx_buf = NULL; /* to-do */ dev->get_rx_buf = NULL; /* upcall is from rmode driver */ dev->peek_rx_buf = NULL; dev->release_rx_buf = NULL; return (0); } /* * Search & probe for supported 32-bit (pmode) pcap devices */ #if defined(USE_32BIT_DRIVERS) struct device el2_dev LOCKED_VAR = { "3c503", "EtherLink II", 0, 0,0,0,0,0,0, NULL, el2_probe }; struct device el3_dev LOCKED_VAR = { "3c509", "EtherLink III", 0, 0,0,0,0,0,0, &el2_dev, el3_probe }; struct device tc515_dev LOCKED_VAR = { "3c515", "EtherLink PCI", 0, 0,0,0,0,0,0, &el3_dev, tc515_probe }; struct device tc59_dev LOCKED_VAR = { "3c59x", "EtherLink PCI", 0, 0,0,0,0,0,0, &tc515_dev, tc59x_probe }; struct device tc90xbc_dev LOCKED_VAR = { "3c90x", "EtherLink 90X", 0, 0,0,0,0,0,0, &tc59_dev, tc90xbc_probe }; struct device wd_dev LOCKED_VAR = { "wd", "Westen Digital", 0, 0,0,0,0,0,0, &tc90xbc_dev, wd_probe }; struct device ne_dev LOCKED_VAR = { "ne", "NEx000", 0, 0,0,0,0,0,0, &wd_dev, ne_probe }; struct device acct_dev LOCKED_VAR = { "acct", "Accton EtherPocket", 0, 0,0,0,0,0,0, &ne_dev, ethpk_probe }; struct device cs89_dev LOCKED_VAR = { "cs89", "Crystal Semiconductor", 0, 0,0,0,0,0,0, &acct_dev, cs89x0_probe }; struct device rtl8139_dev LOCKED_VAR = { "rtl8139", "RealTek PCI", 0, 0,0,0,0,0,0, &cs89_dev, rtl8139_probe /* dev->probe routine */ }; /* * Dequeue routine is called by polling. * NOTE: the queue-element is not copied, only a pointer is * returned at '*buf' */ int peek_rxbuf (BYTE **buf) { struct rx_elem *tail, *head; PCAP_ASSERT (pktq_check (&active_dev->queue)); DISABLE(); tail = pktq_out_elem (&active_dev->queue); head = pktq_in_elem (&active_dev->queue); ENABLE(); if (head != tail) { PCAP_ASSERT (tail->size < active_dev->queue.elem_size-4-2); *buf = &tail->data[0]; return (tail->size); } *buf = NULL; return (0); } /* * Release buffer we peeked at above. */ int release_rxbuf (BYTE *buf) { #ifndef NDEBUG struct rx_elem *tail = pktq_out_elem (&active_dev->queue); PCAP_ASSERT (&tail->data[0] == buf); #else ARGSUSED (buf); #endif pktq_inc_out (&active_dev->queue); return (1); } /* * get_rxbuf() routine (in locked code) is called from IRQ handler * to request a buffer. Interrupts are disabled and we have a 32kB stack. */ BYTE *get_rxbuf (int len) { int idx; if (len < ETH_MIN || len > ETH_MAX) return (NULL); idx = pktq_in_index (&active_dev->queue); #ifdef DEBUG { static int fan_idx LOCKED_VAR = 0; writew ("-\\|/"[fan_idx++] | (15 << 8), /* white on black colour */ 0xB8000 + 2*79); /* upper-right corner, 80-col colour screen */ fan_idx &= 3; } /* writew (idx + '0' + 0x0F00, 0xB8000 + 2*78); */ #endif if (idx != active_dev->queue.out_index) { struct rx_elem *head = pktq_in_elem (&active_dev->queue); head->size = len; active_dev->queue.in_index = idx; return (&head->data[0]); } /* !!to-do: drop 25% of the oldest element */ pktq_clear (&active_dev->queue); return (NULL); } /* * Simple ring-buffer queue handler for reception of packets * from network driver. */ #define PKTQ_MARKER 0xDEADBEEF static int pktq_check (struct rx_ringbuf *q) { #ifndef NDEBUG int i; char *buf; #endif if (!q || !q->num_elem || !q->buf_start) return (0); #ifndef NDEBUG buf = q->buf_start; for (i = 0; i < q->num_elem; i++) { buf += q->elem_size; if (*(DWORD*)(buf - sizeof(DWORD)) != PKTQ_MARKER) return (0); } #endif return (1); } static int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool) { int i; q->elem_size = size; q->num_elem = num; q->buf_start = pool; q->in_index = 0; q->out_index = 0; PCAP_ASSERT (size >= sizeof(struct rx_elem) + sizeof(DWORD)); PCAP_ASSERT (num); PCAP_ASSERT (pool); for (i = 0; i < num; i++) { #if 0 struct rx_elem *elem = (struct rx_elem*) pool; /* assert dword aligned elements */ PCAP_ASSERT (((unsigned)(&elem->data[0]) & 3) == 0); #endif pool += size; *(DWORD*) (pool - sizeof(DWORD)) = PKTQ_MARKER; } return (1); } /* * Increment the queue 'out_index' (tail). * Check for wraps. */ static int pktq_inc_out (struct rx_ringbuf *q) { q->out_index++; if (q->out_index >= q->num_elem) q->out_index = 0; return (q->out_index); } /* * Return the queue's next 'in_index' (head). * Check for wraps. */ static int pktq_in_index (struct rx_ringbuf *q) { volatile int index = q->in_index + 1; if (index >= q->num_elem) index = 0; return (index); } /* * Return the queue's head-buffer. */ static struct rx_elem *pktq_in_elem (struct rx_ringbuf *q) { return (struct rx_elem*) (q->buf_start + (q->elem_size * q->in_index)); } /* * Return the queue's tail-buffer. */ static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q) { return (struct rx_elem*) (q->buf_start + (q->elem_size * q->out_index)); } /* * Clear the queue ring-buffer by setting head=tail. */ static void pktq_clear (struct rx_ringbuf *q) { q->in_index = q->out_index; } /* * Symbols that must be linkable for "gcc -O0" */ #undef __IOPORT_H #undef __DMA_H #define extern #define __inline__ #include "msdos/pm_drvr/ioport.h" #include "msdos/pm_drvr/dma.h" #endif /* USE_32BIT_DRIVERS */ libpcap-1.8.1/VERSION0000644000026300017510000000000613003772130012316 0ustar mcrmcr1.8.1 libpcap-1.8.1/pcap-common.h0000644000026300017510000000167313003771737013657 0ustar mcrmcr /* * We use the "receiver-makes-right" approach to byte order, * because time is at a premium when we are writing the file. * In other words, the pcap_file_header and pcap_pkthdr, * records are written in host byte order. * Note that the bytes of packet data are written out in the order in * which they were received, so multi-byte fields in packets are not * written in host byte order, they're written in whatever order the * sending machine put them in. * * ntoh[ls] aren't sufficient because we might need to swap on a big-endian * machine (if the file was written in little-end order). */ #define SWAPLONG(y) \ ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) #define SWAPSHORT(y) \ ( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>>8) ) extern int dlt_to_linktype(int dlt); extern int linktype_to_dlt(int linktype); extern void swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data); libpcap-1.8.1/pcap_compile.3pcap.in0000644000026300017510000000514413003771737015262 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_COMPILE 3PCAP "7 April 2014" .SH NAME pcap_compile \- compile a filter expression .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_compile(pcap_t *p, struct bpf_program *fp, .ti +8 const char *str, int optimize, bpf_u_int32 netmask); .ft .fi .SH DESCRIPTION .B pcap_compile() is used to compile the string .I str into a filter program. See .BR pcap-filter (@MAN_MISC_INFO@) for the syntax of that string. .I program is a pointer to a .I bpf_program struct and is filled in by .BR pcap_compile() . .I optimize controls whether optimization on the resulting code is performed. .I netmask specifies the IPv4 netmask of the network on which packets are being captured; it is used only when checking for IPv4 broadcast addresses in the filter program. If the netmask of the network on which packets are being captured isn't known to the program, or if packets are being captured on the Linux "any" pseudo-interface that can capture on more than one network, a value of PCAP_NETMASK_UNKNOWN can be supplied; tests for IPv4 broadcast addresses will fail to compile, but all other tests in the filter program will be OK. .SH RETURN VALUE .B pcap_compile() returns 0 on success and \-1 on failure. If \-1 is returned, .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO pcap(3PCAP), pcap_setfilter(3PCAP), pcap_freecode(3PCAP), pcap_geterr(3PCAP), pcap-filter(@MAN_MISC_INFO@) libpcap-1.8.1/Win32/0000755000026300017510000000000013003775545012171 5ustar mcrmcrlibpcap-1.8.1/Win32/Prj/0000755000026300017510000000000013003775545012724 5ustar mcrmcrlibpcap-1.8.1/Win32/Prj/wpcap.vcxproj0000644000026300017510000003253413003771737015461 0ustar mcrmcr Debug Win32 Debug x64 Release Win32 Release x64 {8E92D840-6A36-452A-A13C-6E1BA5A2C5A9} DynamicLibrary v120 false MultiByte DynamicLibrary v120 false MultiByte DynamicLibrary v120 false MultiByte true DynamicLibrary v120 false MultiByte true .\Release\ .\Release\ false ../../../;$(IncludePath) false ../../../;$(IncludePath) .\Debug\ .\Debug\ true ../../../;$(IncludePath) true ../../../;$(IncludePath) MultiThreaded Default true true MaxSpeed true Level3 ../../;../../lbl/;../../bpf/;../include/;../../../../common;../../../../dag/include;../../../../dag/drv/windows;../../../Win32-Extensions;./;Win32-Extensions;%(AdditionalIncludeDirectories) HAVE_VERSION_H;__STDC_VERSION__=199901L;HAVE_PACKET_IS_LOOPBACK_ADAPTER;NDEBUG;YY_NEVER_INTERACTIVE;_USRDLL;BUILDING_PCAP;HAVE_STRERROR;__STDC__;INET6;_WINDOWS;HAVE_ADDRINFO;HAVE_REMOTE;WIN32;_U_=;YY_NO_UNISTD_H;%(PreprocessorDefinitions) 0x0409 NDEBUG;%(PreprocessorDefinitions) ws2_32.lib;..\..\..\..\packetWin7\Dll\Project\Release No NetMon and AirPcap\Packet.lib;%(AdditionalDependencies) call ..\..\GenVersion.bat ..\..\VERSION ..\..\pcap_version.h.in ..\..\pcap_version.h win_flex -Ppcap_ -7 --outfile=..\..\scanner.c --header-file=..\..\scanner.h ..\..\scanner.l win_bison -ppcap_ --yacc --output=..\..\grammar.c --defines ..\..\grammar.y MultiThreaded Default true true MaxSpeed true Level3 ../../;../../lbl/;../../bpf/;../include/;../../../../common;../../../../dag/include;../../../../dag/drv/windows;../../../Win32-Extensions;./;Win32-Extensions;%(AdditionalIncludeDirectories) HAVE_VERSION_H;__STDC_VERSION__=199901L;HAVE_PACKET_IS_LOOPBACK_ADAPTER;NDEBUG;YY_NEVER_INTERACTIVE;_USRDLL;BUILDING_PCAP;HAVE_STRERROR;__STDC__;INET6;_WINDOWS;HAVE_ADDRINFO;HAVE_REMOTE;WIN32;_U_=;YY_NO_UNISTD_H;%(PreprocessorDefinitions) 0x0409 NDEBUG;%(PreprocessorDefinitions) ws2_32.lib;..\..\..\..\packetWin7\Dll\Project\x64\Release No NetMon and AirPcap\Packet.lib;%(AdditionalDependencies) call ..\..\GenVersion.bat ..\..\VERSION ..\..\pcap_version.h.in ..\..\pcap_version.h win_flex -Ppcap_ -7 --outfile=..\..\scanner.c --header-file=..\..\scanner.h ..\..\scanner.l win_bison -ppcap_ --yacc --output=..\..\grammar.c --defines ..\..\grammar.y MultiThreadedDebug Default false Disabled true Level3 true EditAndContinue ../../;../../lbl/;../../bpf/;../include/;../../../../common;../../../../dag/include;../../../../dag/drv/windows;../../../Win32-Extensions;./;Win32-Extensions;%(AdditionalIncludeDirectories) HAVE_VERSION_H;__STDC_VERSION__=199901L;HAVE_PACKET_IS_LOOPBACK_ADAPTER;_DEBUG;YY_NEVER_INTERACTIVE;_USRDLL;BUILDING_PCAP;HAVE_STRERROR;__STDC__;INET6;_WINDOWS;HAVE_ADDRINFO;HAVE_REMOTE;WIN32;_U_=;YY_NO_UNISTD_H;%(PreprocessorDefinitions) EnableFastChecks 0x0409 _DEBUG;%(PreprocessorDefinitions) ws2_32.lib;..\..\..\..\packetWin7\Dll\Project\Release No NetMon and AirPcap\Packet.lib;%(AdditionalDependencies) call ..\..\GenVersion.bat ..\..\VERSION ..\..\pcap_version.h.in ..\..\pcap_version.h win_flex -Ppcap_ -7 --outfile=..\..\scanner.c --header-file=..\..\scanner.h ..\..\scanner.l win_bison -ppcap_ --yacc --output=..\..\grammar.c --defines ..\..\grammar.y MultiThreadedDebug Default false Disabled true Level3 ProgramDatabase ../../;../../lbl/;../../bpf/;../include/;../../../../common;../../../../dag/include;../../../../dag/drv/windows;../../../Win32-Extensions;./;Win32-Extensions;%(AdditionalIncludeDirectories) HAVE_VERSION_H;__STDC_VERSION__=199901L;HAVE_PACKET_IS_LOOPBACK_ADAPTER;_DEBUG;YY_NEVER_INTERACTIVE;_USRDLL;BUILDING_PCAP;HAVE_STRERROR;__STDC__;INET6;_WINDOWS;HAVE_ADDRINFO;HAVE_REMOTE;WIN32;_U_=;YY_NO_UNISTD_H;%(PreprocessorDefinitions) EnableFastChecks 0x0409 _DEBUG;%(PreprocessorDefinitions) ws2_32.lib;..\..\..\..\packetWin7\Dll\Project\x64\Release No NetMon and AirPcap\Packet.lib;%(AdditionalDependencies) call ..\..\GenVersion.bat ..\..\VERSION ..\..\pcap_version.h.in ..\..\pcap_version.h win_flex -Ppcap_ -7 --outfile=..\..\scanner.c --header-file=..\..\scanner.h ..\..\scanner.l win_bison -ppcap_ --yacc --output=..\..\grammar.c --defines ..\..\grammar.y libpcap-1.8.1/Win32/Prj/wpcap.vcxproj.filters0000644000026300017510000000666313003771737017134 0ustar mcrmcr Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files {c51dce5e-0da9-4e33-a235-d5c76c76485c} {5ec9fd4b-10b5-4527-b249-56b53d844fb1} {c90886f0-8973-436b-a7a1-b9e881544f9a} Header Files Header Files Header Files Header Files Header Files Header Files Header Files Resource Files libpcap-1.8.1/Win32/Prj/wpcap.sln0000644000026300017510000000240113003771737014550 0ustar mcrmcr Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpcap", "wpcap.vcxproj", "{8E92D840-6A36-452A-A13C-6E1BA5A2C5A9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {8E92D840-6A36-452A-A13C-6E1BA5A2C5A9}.Debug|Win32.ActiveCfg = Debug|Win32 {8E92D840-6A36-452A-A13C-6E1BA5A2C5A9}.Debug|Win32.Build.0 = Debug|Win32 {8E92D840-6A36-452A-A13C-6E1BA5A2C5A9}.Debug|x64.ActiveCfg = Debug|x64 {8E92D840-6A36-452A-A13C-6E1BA5A2C5A9}.Debug|x64.Build.0 = Debug|x64 {8E92D840-6A36-452A-A13C-6E1BA5A2C5A9}.Release|Win32.ActiveCfg = Release|Win32 {8E92D840-6A36-452A-A13C-6E1BA5A2C5A9}.Release|Win32.Build.0 = Release|Win32 {8E92D840-6A36-452A-A13C-6E1BA5A2C5A9}.Release|x64.ActiveCfg = Release|x64 {8E92D840-6A36-452A-A13C-6E1BA5A2C5A9}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal libpcap-1.8.1/Win32/Include/0000755000026300017510000000000013003775545013554 5ustar mcrmcrlibpcap-1.8.1/Win32/Include/net/0000755000026300017510000000000013003775545014342 5ustar mcrmcrlibpcap-1.8.1/Win32/Include/net/if.h0000644000026300017510000002107713003771737015117 0ustar mcrmcr/* * Copyright (c) 1982, 1986, 1989, 1993 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)if.h 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/net/if.h,v 1.49.2.1 1999/08/29 16:28:15 peter Exp $ */ #ifndef _NET_IF_H_ #define _NET_IF_H_ /* * does not depend on on most other systems. This * helps userland compatability. (struct timeval ifi_lastchange) */ #ifndef KERNEL #include #endif /* * Structure describing information about an interface * which may be of interest to management entities. */ struct if_data { /* generic interface information */ u_char ifi_type; /* ethernet, tokenring, etc */ u_char ifi_physical; /* e.g., AUI, Thinnet, 10base-T, etc */ u_char ifi_addrlen; /* media address length */ u_char ifi_hdrlen; /* media header length */ u_char ifi_recvquota; /* polling quota for receive intrs */ u_char ifi_xmitquota; /* polling quota for xmit intrs */ u_long ifi_mtu; /* maximum transmission unit */ u_long ifi_metric; /* routing metric (external only) */ u_long ifi_baudrate; /* linespeed */ /* volatile statistics */ u_long ifi_ipackets; /* packets received on interface */ u_long ifi_ierrors; /* input errors on interface */ u_long ifi_opackets; /* packets sent on interface */ u_long ifi_oerrors; /* output errors on interface */ u_long ifi_collisions; /* collisions on csma interfaces */ u_long ifi_ibytes; /* total number of octets received */ u_long ifi_obytes; /* total number of octets sent */ u_long ifi_imcasts; /* packets received via multicast */ u_long ifi_omcasts; /* packets sent via multicast */ u_long ifi_iqdrops; /* dropped on input, this interface */ u_long ifi_noproto; /* destined for unsupported protocol */ u_long ifi_recvtiming; /* usec spent receiving when timing */ u_long ifi_xmittiming; /* usec spent xmitting when timing */ struct timeval ifi_lastchange; /* time of last administrative change */ }; /* ws2tcpip.h has interface flags: IFF_* */ #if 0 #define IFF_UP 0x1 /* interface is up */ #define IFF_BROADCAST 0x2 /* broadcast address valid */ #define IFF_DEBUG 0x4 /* turn on debugging */ #define IFF_LOOPBACK 0x8 /* is a loopback net */ #define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */ /*#define IFF_NOTRAILERS 0x20 * obsolete: avoid use of trailers */ #define IFF_RUNNING 0x40 /* resources allocated */ #define IFF_NOARP 0x80 /* no address resolution protocol */ #define IFF_PROMISC 0x100 /* receive all packets */ #define IFF_ALLMULTI 0x200 /* receive all multicast packets */ #define IFF_OACTIVE 0x400 /* transmission in progress */ #define IFF_SIMPLEX 0x800 /* can't hear own transmissions */ #define IFF_LINK0 0x1000 /* per link layer defined bit */ #define IFF_LINK1 0x2000 /* per link layer defined bit */ #define IFF_LINK2 0x4000 /* per link layer defined bit */ #define IFF_ALTPHYS IFF_LINK2 /* use alternate physical connection */ #define IFF_MULTICAST 0x8000 /* supports multicast */ #endif /* 0 */ /* flags set internally only: */ #define IFF_CANTCHANGE \ (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\ IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI) #define IFQ_MAXLEN 50 #define IFNET_SLOWHZ 1 /* granularity is 1 second */ /* * Message format for use in obtaining information about interfaces * from getkerninfo and the routing socket */ struct if_msghdr { u_short ifm_msglen; /* to skip over non-understood messages */ u_char ifm_version; /* future binary compatability */ u_char ifm_type; /* message type */ int ifm_addrs; /* like rtm_addrs */ int ifm_flags; /* value of if_flags */ u_short ifm_index; /* index for associated ifp */ struct if_data ifm_data;/* statistics and other data about if */ }; /* * Message format for use in obtaining information about interface addresses * from getkerninfo and the routing socket */ struct ifa_msghdr { u_short ifam_msglen; /* to skip over non-understood messages */ u_char ifam_version; /* future binary compatability */ u_char ifam_type; /* message type */ int ifam_addrs; /* like rtm_addrs */ int ifam_flags; /* value of ifa_flags */ u_short ifam_index; /* index for associated ifp */ int ifam_metric; /* value of ifa_metric */ }; /* * Message format for use in obtaining information about multicast addresses * from the routing socket */ struct ifma_msghdr { u_short ifmam_msglen; /* to skip over non-understood messages */ u_char ifmam_version; /* future binary compatability */ u_char ifmam_type; /* message type */ int ifmam_addrs; /* like rtm_addrs */ int ifmam_flags; /* value of ifa_flags */ u_short ifmam_index; /* index for associated ifp */ }; /* * Interface request structure used for socket * ioctl's. All interface ioctl's must have parameter * definitions which begin with ifr_name. The * remainder may be interface specific. */ struct ifreq { #define IFNAMSIZ 16 char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; short ifru_flags; int ifru_metric; int ifru_mtu; int ifru_phys; int ifru_media; caddr_t ifru_data; } ifr_ifru; #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ #define ifr_flags ifr_ifru.ifru_flags /* flags */ #define ifr_metric ifr_ifru.ifru_metric /* metric */ #define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ #define ifr_phys ifr_ifru.ifru_phys /* physical wire */ #define ifr_media ifr_ifru.ifru_media /* physical media */ #define ifr_data ifr_ifru.ifru_data /* for use by interface */ }; #define _SIZEOF_ADDR_IFREQ(ifr) \ ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \ (sizeof(struct ifreq) - sizeof(struct sockaddr) + \ (ifr).ifr_addr.sa_len) : sizeof(struct ifreq)) struct ifaliasreq { char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ struct sockaddr ifra_addr; struct sockaddr ifra_broadaddr; struct sockaddr ifra_mask; }; struct ifmediareq { char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */ int ifm_current; /* current media options */ int ifm_mask; /* don't care mask */ int ifm_status; /* media status */ int ifm_active; /* active options */ int ifm_count; /* # entries in ifm_ulist array */ int *ifm_ulist; /* media words */ }; /* * Structure used in SIOCGIFCONF request. * Used to retrieve interface configuration * for machine (useful for programs which * must know all networks accessible). */ struct ifconf { int ifc_len; /* size of associated buffer */ union { caddr_t ifcu_buf; struct ifreq *ifcu_req; } ifc_ifcu; #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ #define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ }; #ifdef KERNEL #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_IFADDR); MALLOC_DECLARE(M_IFMADDR); #endif #endif /* XXX - this should go away soon */ #ifdef KERNEL #include #endif #endif /* !_NET_IF_H_ */ libpcap-1.8.1/Win32/Include/Gnuc.h0000644000026300017510000000016013003771737014615 0ustar mcrmcr/* inline foo */ #ifndef __cplusplus #ifdef __GNUC__ #define inline __inline #else #define inline #endif #endif libpcap-1.8.1/pcap_is_swapped.3pcap0000644000026300017510000000362713003771737015367 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_IS_SWAPPED 3PCAP "7 April 2014" .SH NAME pcap_is_swapped \- find out whether a savefile has the native byte order .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_is_swapped(pcap_t *p); .ft .fi .SH DESCRIPTION .B pcap_is_swapped() returns true (1) if .I p refers to a ``savefile'' that uses a different byte order than the current system. For a live capture, it always returns false (0). .PP It must not be called on a pcap descriptor created by .B pcap_create() that has not yet been activated by .BR pcap_activate() . .SH RETURN VALUE .B pcap_datalink() returns true (1) or false (0) on success and .B PCAP_ERROR_NOT_ACTIVATED if called on a capture handle that has been created but not activated. .SH SEE ALSO pcap(3PCAP) libpcap-1.8.1/pcap_loop.3pcap0000644000026300017510000001501513003771737014174 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_LOOP 3PCAP "18 October 2014" .SH NAME pcap_loop, pcap_dispatch \- process packets from a live capture or savefile .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h, .ti +8 const u_char *bytes); .ft .LP .ft B int pcap_loop(pcap_t *p, int cnt, .ti +8 pcap_handler callback, u_char *user); int pcap_dispatch(pcap_t *p, int cnt, .ti +8 pcap_handler callback, u_char *user); .ft .fi .SH DESCRIPTION .B pcap_loop() processes packets from a live capture or ``savefile'' until .I cnt packets are processed, the end of the ``savefile'' is reached when reading from a ``savefile'', .B pcap_breakloop() is called, or an error occurs. It does .B not return when live read timeouts occur. A value of \-1 or 0 for .I cnt is equivalent to infinity, so that packets are processed until another ending condition occurs. .PP .B pcap_dispatch() processes packets from a live capture or ``savefile'' until .I cnt packets are processed, the end of the current bufferful of packets is reached when doing a live capture, the end of the ``savefile'' is reached when reading from a ``savefile'', .B pcap_breakloop() is called, or an error occurs. Thus, when doing a live capture, .I cnt is the maximum number of packets to process before returning, but is not a minimum number; when reading a live capture, only one bufferful of packets is read at a time, so fewer than .I cnt packets may be processed. A value of \-1 or 0 for .I cnt causes all the packets received in one buffer to be processed when reading a live capture, and causes all the packets in the file to be processed when reading a ``savefile''. .PP Note that, when doing a live capture on some platforms, if the read timeout expires when there are no packets available, .B pcap_dispatch() will return 0, even when not in non-blocking mode, as there are no packets to process. Applications should be prepared for this to happen, but must not rely on it happening. .PP .ft B (In older versions of libpcap, the behavior when \fIcnt\fP was 0 was undefined; different platforms and devices behaved differently, so code that must work with older versions of libpcap should use \-1, not 0, as the value of \fIcnt\fP.) .ft R .PP .I callback specifies a .I pcap_handler routine to be called with three arguments: a .I u_char pointer which is passed in the .I user argument to .B pcap_loop() or .BR pcap_dispatch() , a .I const struct pcap_pkthdr pointer pointing to the packet time stamp and lengths, and a .I const u_char pointer to the first .B caplen (as given in the .I struct pcap_pkthdr a pointer to which is passed to the callback routine) bytes of data from the packet. The .I struct pcap_pkthdr and the packet data are not to be freed by the callback routine, and are not guaranteed to be valid after the callback routine returns; if the code needs them to be valid after the callback, it must make a copy of them. .PP The bytes of data from the packet begin with a link-layer header. The format of the link-layer header is indicated by the return value of the .B pcap_datalink() routine when handed the .B pcap_t value also passed to .B pcap_loop() or .BR pcap_dispatch() . .I http://www.tcpdump.org/linktypes.html lists the values .B pcap_datalink() can return and describes the packet formats that correspond to those values. The value it returns will be valid for all packets received unless and until .B pcap_set_datalink() is called; after a successful call to .BR pcap_set_datalink() , all subsequent packets will have a link-layer header of the type specified by the link-layer header type value passed to .BR pcap_set_datalink() . .PP Do .B NOT assume that the packets for a given capture or ``savefile`` will have any given link-layer header type, such as .B DLT_EN10MB for Ethernet. For example, the "any" device on Linux will have a link-layer header type of .B DLT_LINUX_SLL even if all devices on the system at the time the "any" device is opened have some other data link type, such as .B DLT_EN10MB for Ethernet. .SH RETURN VALUE .B pcap_loop() returns 0 if .I cnt is exhausted or if, when reading from a ``savefile'', no more packets are available. It returns \-1 if an error occurs or \-2 if the loop terminated due to a call to .B pcap_breakloop() before any packets were processed. It does .B not return when live read timeouts occur; instead, it attempts to read more packets. .PP .B pcap_dispatch() returns the number of packets processed on success; this can be 0 if no packets were read from a live capture (if, for example, they were discarded because they didn't pass the packet filter, or if, on platforms that support a read timeout that starts before any packets arrive, the timeout expires before any packets arrive, or if the file descriptor for the capture device is in non-blocking mode and no packets were available to be read) or if no more packets are available in a ``savefile.'' It returns \-1 if an error occurs or \-2 if the loop terminated due to a call to .B pcap_breakloop() before any packets were processed. .ft B If your application uses pcap_breakloop(), make sure that you explicitly check for \-1 and \-2, rather than just checking for a return value < 0. .ft R .PP If \-1 is returned, .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO pcap(3PCAP), pcap_geterr(3PCAP), pcap_breakloop(3PCAP), pcap_datalink(3PCAP) libpcap-1.8.1/pcap-snf.c0000644000026300017510000002713513003771737013151 0ustar mcrmcr#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #if SNF_VERSION_API >= 0x0003 #define SNF_HAVE_INJECT_API #endif #include "pcap-int.h" #include "pcap-snf.h" /* * Private data for capturing on SNF devices. */ struct pcap_snf { snf_handle_t snf_handle; /* opaque device handle */ snf_ring_t snf_ring; /* opaque device ring handle */ #ifdef SNF_HAVE_INJECT_API snf_inject_t snf_inj; /* inject handle, if inject is used */ #endif int snf_timeout; int snf_boardnum; }; static int snf_set_datalink(pcap_t *p, int dlt) { p->linktype = dlt; return (0); } static int snf_pcap_stats(pcap_t *p, struct pcap_stat *ps) { struct snf_ring_stats stats; struct pcap_snf *snfps = p->priv; int rc; if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_get_stats: %s", pcap_strerror(rc)); return -1; } ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow; ps->ps_drop = stats.ring_pkt_overflow; ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad; return 0; } static void snf_platform_cleanup(pcap_t *p) { struct pcap_snf *ps = p->priv; #ifdef SNF_HAVE_INJECT_API if (ps->snf_inj) snf_inject_close(ps->snf_inj); #endif snf_ring_close(ps->snf_ring); snf_close(ps->snf_handle); pcap_cleanup_live_common(p); } static int snf_getnonblock(pcap_t *p, char *errbuf) { struct pcap_snf *ps = p->priv; return (ps->snf_timeout == 0); } static int snf_setnonblock(pcap_t *p, int nonblock, char *errbuf) { struct pcap_snf *ps = p->priv; if (nonblock) ps->snf_timeout = 0; else { if (p->opt.timeout <= 0) ps->snf_timeout = -1; /* forever */ else ps->snf_timeout = p->opt.timeout; } return (0); } #define _NSEC_PER_SEC 1000000000 static inline struct timeval snf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision) { struct timeval tv; long tv_nsec; if (ts_nanosec == 0) return (struct timeval) { 0, 0 }; tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; tv_nsec = (ts_nanosec % _NSEC_PER_SEC); /* libpcap expects tv_usec to be nanos if using nanosecond precision. */ if (tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) tv.tv_usec = tv_nsec; else tv.tv_usec = tv_nsec / 1000; return tv; } static int snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct pcap_snf *ps = p->priv; struct pcap_pkthdr hdr; int i, flags, err, caplen, n; struct snf_recv_req req; int nonblock, timeout; if (!p) return -1; n = 0; timeout = ps->snf_timeout; while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) { /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return (-2); } else { return (n); } } err = snf_ring_recv(ps->snf_ring, timeout, &req); if (err) { if (err == EBUSY || err == EAGAIN) { return (n); } else if (err == EINTR) { timeout = 0; continue; } else { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_read: %s", pcap_strerror(err)); return -1; } } caplen = req.length; if (caplen > p->snapshot) caplen = p->snapshot; if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision); hdr.caplen = caplen; hdr.len = req.length; callback(user, &hdr, req.pkt_addr); } n++; /* After one successful packet is received, we won't block * again for that timeout. */ if (timeout != 0) timeout = 0; } return (n); } static int snf_setfilter(pcap_t *p, struct bpf_program *fp) { if (!p) return -1; if (!fp) { strncpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf)); return -1; } /* Make our private copy of the filter */ if (install_bpf_program(p, fp) < 0) return -1; return (0); } static int snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) { #ifdef SNF_HAVE_INJECT_API struct pcap_snf *ps = p->priv; int rc; if (ps->snf_inj == NULL) { rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj); if (rc) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_inject_open: %s", pcap_strerror(rc)); return (-1); } } rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size); if (!rc) { return (size); } else { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_inject_send: %s", pcap_strerror(rc)); return (-1); } #else strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", PCAP_ERRBUF_SIZE); return (-1); #endif } static int snf_activate(pcap_t* p) { struct pcap_snf *ps = p->priv; char *device = p->opt.device; const char *nr = NULL; int err; int flags = -1, ring_id = -1; if (device == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno)); return -1; } /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. * Since libpcap isn't thread-safe */ if ((nr = getenv("SNF_FLAGS")) && *nr) flags = strtol(nr, NULL, 0); else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) flags = SNF_F_PSHARED; else nr = NULL; err = snf_open(ps->snf_boardnum, 0, /* let SNF API parse SNF_NUM_RINGS, if set */ NULL, /* default RSS, or use SNF_RSS_FLAGS env */ 0, /* default to SNF_DATARING_SIZE from env */ flags, /* may want pshared */ &ps->snf_handle); if (err != 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_open failed: %s", pcap_strerror(err)); return -1; } if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) { ring_id = (int) strtol(nr, NULL, 0); } err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring); if (err != 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_ring_open_id(ring=%d) failed: %s", ring_id, pcap_strerror(err)); return -1; } if (p->opt.timeout <= 0) ps->snf_timeout = -1; else ps->snf_timeout = p->opt.timeout; err = snf_start(ps->snf_handle); if (err != 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_start failed: %s", pcap_strerror(err)); return -1; } /* * "select()" and "poll()" don't work on snf descriptors. */ p->selectable_fd = -1; p->linktype = DLT_EN10MB; p->read_op = snf_read; p->inject_op = snf_inject; p->setfilter_op = snf_setfilter; p->setdirection_op = NULL; /* Not implemented.*/ p->set_datalink_op = snf_set_datalink; p->getnonblock_op = snf_getnonblock; p->setnonblock_op = snf_setnonblock; p->stats_op = snf_pcap_stats; p->cleanup_op = snf_platform_cleanup; #ifdef SNF_HAVE_INJECT_API ps->snf_inj = NULL; #endif return 0; } #define MAX_DESC_LENGTH 128 int snf_findalldevs(pcap_if_t **devlistp, char *errbuf) { pcap_if_t *devlist = NULL,*curdev,*prevdev; pcap_addr_t *curaddr; struct snf_ifaddrs *ifaddrs, *ifa; char desc[MAX_DESC_LENGTH]; int ret; if (snf_init(SNF_VERSION_API)) return (-1); if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "snf_getifaddrs: %s", pcap_strerror(errno)); return (-1); } ifa = ifaddrs; while (ifa) { /* * Allocate a new entry */ curdev = (pcap_if_t *)malloc(sizeof(pcap_if_t)); if (curdev == NULL) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "snf_findalldevs malloc: %s", pcap_strerror(errno)); return (-1); } if (devlist == NULL) /* save first entry */ devlist = curdev; else prevdev->next = curdev; /* * Fill in the entry. */ curdev->next = NULL; curdev->name = strdup(ifa->snf_ifa_name); if (curdev->name == NULL) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "snf_findalldevs strdup: %s", pcap_strerror(errno)); free(curdev); return (-1); } (void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom snf%d", ifa->snf_ifa_portnum); curdev->description = strdup(desc); if (curdev->description == NULL) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "snf_findalldevs strdup1: %s", pcap_strerror(errno)); free(curdev->name); free(curdev); return (-1); } curdev->addresses = NULL; curdev->flags = 0; curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t)); if (curaddr == NULL) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "snf_findalldevs malloc1: %s", pcap_strerror(errno)); free(curdev->description); free(curdev->name); free(curdev); return (-1); } curdev->addresses = curaddr; curaddr->next = NULL; curaddr->addr = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage)); if (curaddr->addr == NULL) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc2: %s", pcap_strerror(errno)); free(curdev->description); free(curdev->name); free(curaddr); free(curdev); return (-1); } curaddr->addr->sa_family = AF_INET; curaddr->netmask = NULL; curaddr->broadaddr = NULL; curaddr->dstaddr = NULL; curaddr->next = NULL; prevdev = curdev; ifa = ifa->snf_ifa_next; } snf_freeifaddrs(ifaddrs); *devlistp = devlist; /* * There are no platform-specific devices since each device * exists as a regular Ethernet device. */ return 0; } pcap_t * snf_create(const char *device, char *ebuf, int *is_ours) { pcap_t *p; int boardnum = -1; struct snf_ifaddrs *ifaddrs, *ifa; size_t devlen; struct pcap_snf *ps; if (snf_init(SNF_VERSION_API)) { /* Can't initialize the API, so no SNF devices */ *is_ours = 0; return NULL; } /* * Match a given interface name to our list of interface names, from * which we can obtain the intended board number */ if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { /* Can't get SNF addresses */ *is_ours = 0; return NULL; } devlen = strlen(device) + 1; ifa = ifaddrs; while (ifa) { if (!strncmp(device, ifa->snf_ifa_name, devlen)) { boardnum = ifa->snf_ifa_boardnum; break; } ifa = ifa->snf_ifa_next; } snf_freeifaddrs(ifaddrs); if (ifa == NULL) { /* * If we can't find the device by name, support the name "snfX" * and "snf10gX" where X is the board number. */ if (sscanf(device, "snf10g%d", &boardnum) != 1 && sscanf(device, "snf%d", &boardnum) != 1) { /* Nope, not a supported name */ *is_ours = 0; return NULL; } } /* OK, it's probably ours. */ *is_ours = 1; p = pcap_create_common(ebuf, sizeof (struct pcap_snf)); if (p == NULL) return NULL; ps = p->priv; /* * We support microsecond and nanosecond time stamps. */ p->tstamp_precision_count = 2; p->tstamp_precision_list = malloc(2 * sizeof(u_int)); if (p->tstamp_precision_list == NULL) { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); pcap_close(p); return NULL; } p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; p->activate_op = snf_activate; ps->snf_boardnum = boardnum; return p; } #ifdef SNF_ONLY /* * This libpcap build supports only SNF cards, not regular network * interfaces.. */ /* * There are no regular interfaces, just DAG interfaces. */ int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { *alldevsp = NULL; return (0); } /* * Attempts to open a regular interface fail. */ pcap_t * pcap_create_interface(const char *device, char *errbuf) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "This version of libpcap only supports SNF cards"); return NULL; } #endif libpcap-1.8.1/gencode.c0000644000026300017510000071437613003771737013060 0ustar mcrmcr/*#define CHASE_CHAIN*/ /* * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 * 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef _WIN32 #include #else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_BITYPES_H #include #endif #include #include #endif /* _WIN32 */ #ifndef _WIN32 #ifdef __NetBSD__ #include #endif #include #include #endif /* _WIN32 */ #include #include #include #include #include #ifdef MSDOS #include "pcap-dos.h" #endif #include "pcap-int.h" #include "ethertype.h" #include "nlpid.h" #include "llc.h" #include "gencode.h" #include "ieee80211.h" #include "atmuni31.h" #include "sunatmpos.h" #include "ppp.h" #include "pcap/sll.h" #include "pcap/ipnet.h" #include "arcnet.h" #include "grammar.h" #include "scanner.h" #if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) #include #include #include #endif #ifdef HAVE_NET_PFVAR_H #include #include #include #include #endif #ifndef offsetof #define offsetof(s, e) ((size_t)&((s *)0)->e) #endif #ifdef INET6 #ifdef _WIN32 #if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) /* IPv6 address */ struct in6_addr { union { u_int8_t u6_addr8[16]; u_int16_t u6_addr16[8]; u_int32_t u6_addr32[4]; } in6_u; #define s6_addr in6_u.u6_addr8 #define s6_addr16 in6_u.u6_addr16 #define s6_addr32 in6_u.u6_addr32 #define s6_addr64 in6_u.u6_addr64 }; typedef unsigned short sa_family_t; #define __SOCKADDR_COMMON(sa_prefix) \ sa_family_t sa_prefix##family /* Ditto, for IPv6. */ struct sockaddr_in6 { __SOCKADDR_COMMON (sin6_); u_int16_t sin6_port; /* Transport layer port # */ u_int32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ }; #ifndef EAI_ADDRFAMILY struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for hostname */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; #endif /* EAI_ADDRFAMILY */ #endif /* defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) */ #else /* _WIN32 */ #include /* for "struct addrinfo" */ #endif /* _WIN32 */ #endif /* INET6 */ #include #include "nametoaddr.h" #define ETHERMTU 1500 #ifndef ETHERTYPE_TEB #define ETHERTYPE_TEB 0x6558 #endif #ifndef IPPROTO_HOPOPTS #define IPPROTO_HOPOPTS 0 #endif #ifndef IPPROTO_ROUTING #define IPPROTO_ROUTING 43 #endif #ifndef IPPROTO_FRAGMENT #define IPPROTO_FRAGMENT 44 #endif #ifndef IPPROTO_DSTOPTS #define IPPROTO_DSTOPTS 60 #endif #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 #endif #define GENEVE_PORT 6081 #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #define JMP(c) ((c)|BPF_JMP|BPF_K) /* * "Push" the current value of the link-layer header type and link-layer * header offset onto a "stack", and set a new value. (It's not a * full-blown stack; we keep only the top two items.) */ #define PUSH_LINKHDR(cs, new_linktype, new_is_variable, new_constant_part, new_reg) \ { \ (cs)->prevlinktype = (cs)->linktype; \ (cs)->off_prevlinkhdr = (cs)->off_linkhdr; \ (cs)->linktype = (new_linktype); \ (cs)->off_linkhdr.is_variable = (new_is_variable); \ (cs)->off_linkhdr.constant_part = (new_constant_part); \ (cs)->off_linkhdr.reg = (new_reg); \ (cs)->is_geneve = 0; \ } /* * Offset "not set" value. */ #define OFFSET_NOT_SET 0xffffffffU /* * Absolute offsets, which are offsets from the beginning of the raw * packet data, are, in the general case, the sum of a variable value * and a constant value; the variable value may be absent, in which * case the offset is only the constant value, and the constant value * may be zero, in which case the offset is only the variable value. * * bpf_abs_offset is a structure containing all that information: * * is_variable is 1 if there's a variable part. * * constant_part is the constant part of the value, possibly zero; * * if is_variable is 1, reg is the register number for a register * containing the variable value if the register has been assigned, * and -1 otherwise. */ typedef struct { int is_variable; u_int constant_part; int reg; } bpf_abs_offset; /* * Value passed to gen_load_a() to indicate what the offset argument * is relative to the beginning of. */ enum e_offrel { OR_PACKET, /* full packet data */ OR_LINKHDR, /* link-layer header */ OR_PREVLINKHDR, /* previous link-layer header */ OR_LLC, /* 802.2 LLC header */ OR_PREVMPLSHDR, /* previous MPLS header */ OR_LINKTYPE, /* link-layer type */ OR_LINKPL, /* link-layer payload */ OR_LINKPL_NOSNAP, /* link-layer payload, with no SNAP header at the link layer */ OR_TRAN_IPV4, /* transport-layer header, with IPv4 network layer */ OR_TRAN_IPV6 /* transport-layer header, with IPv6 network layer */ }; /* * We divy out chunks of memory rather than call malloc each time so * we don't have to worry about leaking memory. It's probably * not a big deal if all this memory was wasted but if this ever * goes into a library that would probably not be a good idea. * * XXX - this *is* in a library.... */ #define NCHUNKS 16 #define CHUNK0SIZE 1024 struct chunk { size_t n_left; void *m; }; /* Code generator state */ struct _compiler_state { jmp_buf top_ctx; pcap_t *bpf_pcap; struct icode ic; int snaplen; int linktype; int prevlinktype; int outermostlinktype; bpf_u_int32 netmask; int no_optimize; /* Hack for handling VLAN and MPLS stacks. */ u_int label_stack_depth; u_int vlan_stack_depth; /* XXX */ u_int pcap_fddipad; #ifdef INET6 /* * As errors are handled by a longjmp, anything allocated must * be freed in the longjmp handler, so it must be reachable * from that handler. * * One thing that's allocated is the result of pcap_nametoaddrinfo(); * it must be freed with freeaddrinfo(). This variable points to * any addrinfo structure that would need to be freed. */ struct addrinfo *ai; #endif /* * Various code constructs need to know the layout of the packet. * These values give the necessary offsets from the beginning * of the packet data. */ /* * Absolute offset of the beginning of the link-layer header. */ bpf_abs_offset off_linkhdr; /* * If we're checking a link-layer header for a packet encapsulated * in another protocol layer, this is the equivalent information * for the previous layers' link-layer header from the beginning * of the raw packet data. */ bpf_abs_offset off_prevlinkhdr; /* * This is the equivalent information for the outermost layers' * link-layer header. */ bpf_abs_offset off_outermostlinkhdr; /* * Absolute offset of the beginning of the link-layer payload. */ bpf_abs_offset off_linkpl; /* * "off_linktype" is the offset to information in the link-layer * header giving the packet type. This is an absolute offset * from the beginning of the packet. * * For Ethernet, it's the offset of the Ethernet type field; this * means that it must have a value that skips VLAN tags. * * For link-layer types that always use 802.2 headers, it's the * offset of the LLC header; this means that it must have a value * that skips VLAN tags. * * For PPP, it's the offset of the PPP type field. * * For Cisco HDLC, it's the offset of the CHDLC type field. * * For BSD loopback, it's the offset of the AF_ value. * * For Linux cooked sockets, it's the offset of the type field. * * off_linktype.constant_part is set to OFFSET_NOT_SET for no * encapsulation, in which case, IP is assumed. */ bpf_abs_offset off_linktype; /* * TRUE if the link layer includes an ATM pseudo-header. */ int is_atm; /* * TRUE if "geneve" appeared in the filter; it causes us to * generate code that checks for a Geneve header and assume * that later filters apply to the encapsulated payload. */ int is_geneve; /* * These are offsets for the ATM pseudo-header. */ u_int off_vpi; u_int off_vci; u_int off_proto; /* * These are offsets for the MTP2 fields. */ u_int off_li; u_int off_li_hsl; /* * These are offsets for the MTP3 fields. */ u_int off_sio; u_int off_opc; u_int off_dpc; u_int off_sls; /* * This is the offset of the first byte after the ATM pseudo_header, * or -1 if there is no ATM pseudo-header. */ u_int off_payload; /* * These are offsets to the beginning of the network-layer header. * They are relative to the beginning of the link-layer payload * (i.e., they don't include off_linkhdr.constant_part or * off_linkpl.constant_part). * * If the link layer never uses 802.2 LLC: * * "off_nl" and "off_nl_nosnap" are the same. * * If the link layer always uses 802.2 LLC: * * "off_nl" is the offset if there's a SNAP header following * the 802.2 header; * * "off_nl_nosnap" is the offset if there's no SNAP header. * * If the link layer is Ethernet: * * "off_nl" is the offset if the packet is an Ethernet II packet * (we assume no 802.3+802.2+SNAP); * * "off_nl_nosnap" is the offset if the packet is an 802.3 packet * with an 802.2 header following it. */ u_int off_nl; u_int off_nl_nosnap; /* * Here we handle simple allocation of the scratch registers. * If too many registers are alloc'd, the allocator punts. */ int regused[BPF_MEMWORDS]; int curreg; /* * Memory chunks. */ struct chunk chunks[NCHUNKS]; int cur_chunk; }; void bpf_syntax_error(compiler_state_t *cstate, const char *msg) { bpf_error(cstate, "syntax error in filter expression: %s", msg); /* NOTREACHED */ } /* VARARGS */ void bpf_error(compiler_state_t *cstate, const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (cstate->bpf_pcap != NULL) (void)pcap_vsnprintf(pcap_geterr(cstate->bpf_pcap), PCAP_ERRBUF_SIZE, fmt, ap); va_end(ap); longjmp(cstate->top_ctx, 1); /* NOTREACHED */ } static void init_linktype(compiler_state_t *, pcap_t *); static void init_regs(compiler_state_t *); static int alloc_reg(compiler_state_t *); static void free_reg(compiler_state_t *, int); static void initchunks(compiler_state_t *cstate); static void *newchunk(compiler_state_t *cstate, size_t); static void freechunks(compiler_state_t *cstate); static inline struct block *new_block(compiler_state_t *cstate, int); static inline struct slist *new_stmt(compiler_state_t *cstate, int); static struct block *gen_retblk(compiler_state_t *cstate, int); static inline void syntax(compiler_state_t *cstate); static void backpatch(struct block *, struct block *); static void merge(struct block *, struct block *); static struct block *gen_cmp(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_int32); static struct block *gen_cmp_gt(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_int32); static struct block *gen_cmp_ge(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_int32); static struct block *gen_cmp_lt(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_int32); static struct block *gen_cmp_le(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_int32); static struct block *gen_mcmp(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_int32, bpf_u_int32); static struct block *gen_bcmp(compiler_state_t *, enum e_offrel, u_int, u_int, const u_char *); static struct block *gen_ncmp(compiler_state_t *, enum e_offrel, bpf_u_int32, bpf_u_int32, bpf_u_int32, bpf_u_int32, int, bpf_int32); static struct slist *gen_load_absoffsetrel(compiler_state_t *, bpf_abs_offset *, u_int, u_int); static struct slist *gen_load_a(compiler_state_t *, enum e_offrel, u_int, u_int); static struct slist *gen_loadx_iphdrlen(compiler_state_t *); static struct block *gen_uncond(compiler_state_t *, int); static inline struct block *gen_true(compiler_state_t *); static inline struct block *gen_false(compiler_state_t *); static struct block *gen_ether_linktype(compiler_state_t *, int); static struct block *gen_ipnet_linktype(compiler_state_t *, int); static struct block *gen_linux_sll_linktype(compiler_state_t *, int); static struct slist *gen_load_prism_llprefixlen(compiler_state_t *); static struct slist *gen_load_avs_llprefixlen(compiler_state_t *); static struct slist *gen_load_radiotap_llprefixlen(compiler_state_t *); static struct slist *gen_load_ppi_llprefixlen(compiler_state_t *); static void insert_compute_vloffsets(compiler_state_t *, struct block *); static struct slist *gen_abs_offset_varpart(compiler_state_t *, bpf_abs_offset *); static int ethertype_to_ppptype(int); static struct block *gen_linktype(compiler_state_t *, int); static struct block *gen_snap(compiler_state_t *, bpf_u_int32, bpf_u_int32); static struct block *gen_llc_linktype(compiler_state_t *, int); static struct block *gen_hostop(compiler_state_t *, bpf_u_int32, bpf_u_int32, int, int, u_int, u_int); #ifdef INET6 static struct block *gen_hostop6(compiler_state_t *, struct in6_addr *, struct in6_addr *, int, int, u_int, u_int); #endif static struct block *gen_ahostop(compiler_state_t *, const u_char *, int); static struct block *gen_ehostop(compiler_state_t *, const u_char *, int); static struct block *gen_fhostop(compiler_state_t *, const u_char *, int); static struct block *gen_thostop(compiler_state_t *, const u_char *, int); static struct block *gen_wlanhostop(compiler_state_t *, const u_char *, int); static struct block *gen_ipfchostop(compiler_state_t *, const u_char *, int); static struct block *gen_dnhostop(compiler_state_t *, bpf_u_int32, int); static struct block *gen_mpls_linktype(compiler_state_t *, int); static struct block *gen_host(compiler_state_t *, bpf_u_int32, bpf_u_int32, int, int, int); #ifdef INET6 static struct block *gen_host6(compiler_state_t *, struct in6_addr *, struct in6_addr *, int, int, int); #endif #ifndef INET6 static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int); #endif static struct block *gen_ipfrag(compiler_state_t *); static struct block *gen_portatom(compiler_state_t *, int, bpf_int32); static struct block *gen_portrangeatom(compiler_state_t *, int, bpf_int32, bpf_int32); static struct block *gen_portatom6(compiler_state_t *, int, bpf_int32); static struct block *gen_portrangeatom6(compiler_state_t *, int, bpf_int32, bpf_int32); struct block *gen_portop(compiler_state_t *, int, int, int); static struct block *gen_port(compiler_state_t *, int, int, int); struct block *gen_portrangeop(compiler_state_t *, int, int, int, int); static struct block *gen_portrange(compiler_state_t *, int, int, int, int); struct block *gen_portop6(compiler_state_t *, int, int, int); static struct block *gen_port6(compiler_state_t *, int, int, int); struct block *gen_portrangeop6(compiler_state_t *, int, int, int, int); static struct block *gen_portrange6(compiler_state_t *, int, int, int, int); static int lookup_proto(compiler_state_t *, const char *, int); static struct block *gen_protochain(compiler_state_t *, int, int, int); static struct block *gen_proto(compiler_state_t *, int, int, int); static struct slist *xfer_to_x(compiler_state_t *, struct arth *); static struct slist *xfer_to_a(compiler_state_t *, struct arth *); static struct block *gen_mac_multicast(compiler_state_t *, int); static struct block *gen_len(compiler_state_t *, int, int); static struct block *gen_check_802_11_data_frame(compiler_state_t *); static struct block *gen_geneve_ll_check(compiler_state_t *cstate); static struct block *gen_ppi_dlt_check(compiler_state_t *); static struct block *gen_msg_abbrev(compiler_state_t *, int type); static void initchunks(compiler_state_t *cstate) { int i; for (i = 0; i < NCHUNKS; i++) { cstate->chunks[i].n_left = 0; cstate->chunks[i].m = NULL; } cstate->cur_chunk = 0; } static void * newchunk(compiler_state_t *cstate, size_t n) { struct chunk *cp; int k; size_t size; #ifndef __NetBSD__ /* XXX Round up to nearest long. */ n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1); #else /* XXX Round up to structure boundary. */ n = ALIGN(n); #endif cp = &cstate->chunks[cstate->cur_chunk]; if (n > cp->n_left) { ++cp, k = ++cstate->cur_chunk; if (k >= NCHUNKS) bpf_error(cstate, "out of memory"); size = CHUNK0SIZE << k; cp->m = (void *)malloc(size); if (cp->m == NULL) bpf_error(cstate, "out of memory"); memset((char *)cp->m, 0, size); cp->n_left = size; if (n > size) bpf_error(cstate, "out of memory"); } cp->n_left -= n; return (void *)((char *)cp->m + cp->n_left); } static void freechunks(compiler_state_t *cstate) { int i; for (i = 0; i < NCHUNKS; ++i) if (cstate->chunks[i].m != NULL) free(cstate->chunks[i].m); } /* * A strdup whose allocations are freed after code generation is over. */ char * sdup(compiler_state_t *cstate, const char *s) { size_t n = strlen(s) + 1; char *cp = newchunk(cstate, n); strlcpy(cp, s, n); return (cp); } static inline struct block * new_block(compiler_state_t *cstate, int code) { struct block *p; p = (struct block *)newchunk(cstate, sizeof(*p)); p->s.code = code; p->head = p; return p; } static inline struct slist * new_stmt(compiler_state_t *cstate, int code) { struct slist *p; p = (struct slist *)newchunk(cstate, sizeof(*p)); p->s.code = code; return p; } static struct block * gen_retblk(compiler_state_t *cstate, int v) { struct block *b = new_block(cstate, BPF_RET|BPF_K); b->s.k = v; return b; } static inline void syntax(compiler_state_t *cstate) { bpf_error(cstate, "syntax error in filter expression"); } int pcap_compile(pcap_t *p, struct bpf_program *program, const char *buf, int optimize, bpf_u_int32 mask) { compiler_state_t cstate; const char * volatile xbuf = buf; yyscan_t scanner = NULL; YY_BUFFER_STATE in_buffer = NULL; u_int len; int rc; #ifdef _WIN32 static int done = 0; if (!done) pcap_wsockinit(); done = 1; #endif /* * If this pcap_t hasn't been activated, it doesn't have a * link-layer type, so we can't use it. */ if (!p->activated) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "not-yet-activated pcap_t passed to pcap_compile"); rc = -1; goto quit; } initchunks(&cstate); cstate.no_optimize = 0; cstate.ai = NULL; cstate.ic.root = NULL; cstate.ic.cur_mark = 0; cstate.bpf_pcap = p; init_regs(&cstate); if (setjmp(cstate.top_ctx)) { #ifdef INET6 if (cstate.ai != NULL) freeaddrinfo(cstate.ai); #endif rc = -1; goto quit; } cstate.netmask = mask; cstate.snaplen = pcap_snapshot(p); if (cstate.snaplen == 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snaplen of 0 rejects all packets"); rc = -1; goto quit; } if (pcap_lex_init(&scanner) != 0) bpf_error(&cstate, "can't initialize scanner: %s", pcap_strerror(errno)); in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner); /* * Associate the compiler state with the lexical analyzer * state. */ pcap_set_extra(&cstate, scanner); init_linktype(&cstate, p); (void)pcap_parse(scanner, &cstate); if (cstate.ic.root == NULL) cstate.ic.root = gen_retblk(&cstate, cstate.snaplen); if (optimize && !cstate.no_optimize) { bpf_optimize(&cstate, &cstate.ic); if (cstate.ic.root == NULL || (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) bpf_error(&cstate, "expression rejects all packets"); } program->bf_insns = icode_to_fcode(&cstate, &cstate.ic, cstate.ic.root, &len); program->bf_len = len; rc = 0; /* We're all okay */ quit: /* * Clean up everything for the lexical analyzer. */ if (in_buffer != NULL) pcap__delete_buffer(in_buffer, scanner); if (scanner != NULL) pcap_lex_destroy(scanner); /* * Clean up our own allocated memory. */ freechunks(&cstate); return (rc); } /* * entry point for using the compiler with no pcap open * pass in all the stuff that is needed explicitly instead. */ int pcap_compile_nopcap(int snaplen_arg, int linktype_arg, struct bpf_program *program, const char *buf, int optimize, bpf_u_int32 mask) { pcap_t *p; int ret; p = pcap_open_dead(linktype_arg, snaplen_arg); if (p == NULL) return (-1); ret = pcap_compile(p, program, buf, optimize, mask); pcap_close(p); return (ret); } /* * Clean up a "struct bpf_program" by freeing all the memory allocated * in it. */ void pcap_freecode(struct bpf_program *program) { program->bf_len = 0; if (program->bf_insns != NULL) { free((char *)program->bf_insns); program->bf_insns = NULL; } } /* * Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates * which of the jt and jf fields has been resolved and which is a pointer * back to another unresolved block (or nil). At least one of the fields * in each block is already resolved. */ static void backpatch(list, target) struct block *list, *target; { struct block *next; while (list) { if (!list->sense) { next = JT(list); JT(list) = target; } else { next = JF(list); JF(list) = target; } list = next; } } /* * Merge the lists in b0 and b1, using the 'sense' field to indicate * which of jt and jf is the link. */ static void merge(b0, b1) struct block *b0, *b1; { register struct block **p = &b0; /* Find end of list. */ while (*p) p = !((*p)->sense) ? &JT(*p) : &JF(*p); /* Concatenate the lists. */ *p = b1; } void finish_parse(compiler_state_t *cstate, struct block *p) { struct block *ppi_dlt_check; /* * Insert before the statements of the first (root) block any * statements needed to load the lengths of any variable-length * headers into registers. * * XXX - a fancier strategy would be to insert those before the * statements of all blocks that use those lengths and that * have no predecessors that use them, so that we only compute * the lengths if we need them. There might be even better * approaches than that. * * However, those strategies would be more complicated, and * as we don't generate code to compute a length if the * program has no tests that use the length, and as most * tests will probably use those lengths, we would just * postpone computing the lengths so that it's not done * for tests that fail early, and it's not clear that's * worth the effort. */ insert_compute_vloffsets(cstate, p->head); /* * For DLT_PPI captures, generate a check of the per-packet * DLT value to make sure it's DLT_IEEE802_11. * * XXX - TurboCap cards use DLT_PPI for Ethernet. * Can we just define some DLT_ETHERNET_WITH_PHDR pseudo-header * with appropriate Ethernet information and use that rather * than using something such as DLT_PPI where you don't know * the link-layer header type until runtime, which, in the * general case, would force us to generate both Ethernet *and* * 802.11 code (*and* anything else for which PPI is used) * and choose between them early in the BPF program? */ ppi_dlt_check = gen_ppi_dlt_check(cstate); if (ppi_dlt_check != NULL) gen_and(ppi_dlt_check, p); backpatch(p, gen_retblk(cstate, cstate->snaplen)); p->sense = !p->sense; backpatch(p, gen_retblk(cstate, 0)); cstate->ic.root = p->head; } void gen_and(b0, b1) struct block *b0, *b1; { backpatch(b0, b1->head); b0->sense = !b0->sense; b1->sense = !b1->sense; merge(b1, b0); b1->sense = !b1->sense; b1->head = b0->head; } void gen_or(b0, b1) struct block *b0, *b1; { b0->sense = !b0->sense; backpatch(b0, b1->head); b0->sense = !b0->sense; merge(b1, b0); b1->head = b0->head; } void gen_not(b) struct block *b; { b->sense = !b->sense; } static struct block * gen_cmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_int32 v) { return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v); } static struct block * gen_cmp_gt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_int32 v) { return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 0, v); } static struct block * gen_cmp_ge(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_int32 v) { return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 0, v); } static struct block * gen_cmp_lt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_int32 v) { return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 1, v); } static struct block * gen_cmp_le(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_int32 v) { return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 1, v); } static struct block * gen_mcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_int32 v, bpf_u_int32 mask) { return gen_ncmp(cstate, offrel, offset, size, mask, BPF_JEQ, 0, v); } static struct block * gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, const u_char *v) { register struct block *b, *tmp; b = NULL; while (size >= 4) { register const u_char *p = &v[size - 4]; bpf_int32 w = ((bpf_int32)p[0] << 24) | ((bpf_int32)p[1] << 16) | ((bpf_int32)p[2] << 8) | p[3]; tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W, w); if (b != NULL) gen_and(b, tmp); b = tmp; size -= 4; } while (size >= 2) { register const u_char *p = &v[size - 2]; bpf_int32 w = ((bpf_int32)p[0] << 8) | p[1]; tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H, w); if (b != NULL) gen_and(b, tmp); b = tmp; size -= 2; } if (size > 0) { tmp = gen_cmp(cstate, offrel, offset, BPF_B, (bpf_int32)v[0]); if (b != NULL) gen_and(b, tmp); b = tmp; } return b; } /* * AND the field of size "size" at offset "offset" relative to the header * specified by "offrel" with "mask", and compare it with the value "v" * with the test specified by "jtype"; if "reverse" is true, the test * should test the opposite of "jtype". */ static struct block * gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, bpf_u_int32 offset, bpf_u_int32 size, bpf_u_int32 mask, bpf_u_int32 jtype, int reverse, bpf_int32 v) { struct slist *s, *s2; struct block *b; s = gen_load_a(cstate, offrel, offset, size); if (mask != 0xffffffff) { s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); s2->s.k = mask; sappend(s, s2); } b = new_block(cstate, JMP(jtype)); b->stmts = s; b->s.k = v; if (reverse && (jtype == BPF_JGT || jtype == BPF_JGE)) gen_not(b); return b; } static void init_linktype(compiler_state_t *cstate, pcap_t *p) { cstate->pcap_fddipad = p->fddipad; /* * We start out with only one link-layer header. */ cstate->outermostlinktype = pcap_datalink(p); cstate->off_outermostlinkhdr.constant_part = 0; cstate->off_outermostlinkhdr.is_variable = 0; cstate->off_outermostlinkhdr.reg = -1; cstate->prevlinktype = cstate->outermostlinktype; cstate->off_prevlinkhdr.constant_part = 0; cstate->off_prevlinkhdr.is_variable = 0; cstate->off_prevlinkhdr.reg = -1; cstate->linktype = cstate->outermostlinktype; cstate->off_linkhdr.constant_part = 0; cstate->off_linkhdr.is_variable = 0; cstate->off_linkhdr.reg = -1; /* * XXX */ cstate->off_linkpl.constant_part = 0; cstate->off_linkpl.is_variable = 0; cstate->off_linkpl.reg = -1; cstate->off_linktype.constant_part = 0; cstate->off_linktype.is_variable = 0; cstate->off_linktype.reg = -1; /* * Assume it's not raw ATM with a pseudo-header, for now. */ cstate->is_atm = 0; cstate->off_vpi = -1; cstate->off_vci = -1; cstate->off_proto = -1; cstate->off_payload = -1; /* * And not Geneve. */ cstate->is_geneve = 0; /* * And assume we're not doing SS7. */ cstate->off_li = -1; cstate->off_li_hsl = -1; cstate->off_sio = -1; cstate->off_opc = -1; cstate->off_dpc = -1; cstate->off_sls = -1; cstate->label_stack_depth = 0; cstate->vlan_stack_depth = 0; switch (cstate->linktype) { case DLT_ARCNET: cstate->off_linktype.constant_part = 2; cstate->off_linkpl.constant_part = 6; cstate->off_nl = 0; /* XXX in reality, variable! */ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_ARCNET_LINUX: cstate->off_linktype.constant_part = 4; cstate->off_linkpl.constant_part = 8; cstate->off_nl = 0; /* XXX in reality, variable! */ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_EN10MB: cstate->off_linktype.constant_part = 12; cstate->off_linkpl.constant_part = 14; /* Ethernet header length */ cstate->off_nl = 0; /* Ethernet II */ cstate->off_nl_nosnap = 3; /* 802.3+802.2 */ break; case DLT_SLIP: /* * SLIP doesn't have a link level type. The 16 byte * header is hacked into our SLIP driver. */ cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = 16; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_SLIP_BSDOS: /* XXX this may be the same as the DLT_PPP_BSDOS case */ cstate->off_linktype.constant_part = OFFSET_NOT_SET; /* XXX end */ cstate->off_linkpl.constant_part = 24; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_NULL: case DLT_LOOP: cstate->off_linktype.constant_part = 0; cstate->off_linkpl.constant_part = 4; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_ENC: cstate->off_linktype.constant_part = 0; cstate->off_linkpl.constant_part = 12; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_PPP: case DLT_PPP_PPPD: case DLT_C_HDLC: /* BSD/OS Cisco HDLC */ case DLT_PPP_SERIAL: /* NetBSD sync/async serial PPP */ cstate->off_linktype.constant_part = 2; /* skip HDLC-like framing */ cstate->off_linkpl.constant_part = 4; /* skip HDLC-like framing and protocol field */ cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_PPP_ETHER: /* * This does no include the Ethernet header, and * only covers session state. */ cstate->off_linktype.constant_part = 6; cstate->off_linkpl.constant_part = 8; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_PPP_BSDOS: cstate->off_linktype.constant_part = 5; cstate->off_linkpl.constant_part = 24; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_FDDI: /* * FDDI doesn't really have a link-level type field. * We set "off_linktype" to the offset of the LLC header. * * To check for Ethernet types, we assume that SSAP = SNAP * is being used and pick out the encapsulated Ethernet type. * XXX - should we generate code to check for SNAP? */ cstate->off_linktype.constant_part = 13; cstate->off_linktype.constant_part += cstate->pcap_fddipad; cstate->off_linkpl.constant_part = 13; /* FDDI MAC header length */ cstate->off_linkpl.constant_part += cstate->pcap_fddipad; cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_IEEE802: /* * Token Ring doesn't really have a link-level type field. * We set "off_linktype" to the offset of the LLC header. * * To check for Ethernet types, we assume that SSAP = SNAP * is being used and pick out the encapsulated Ethernet type. * XXX - should we generate code to check for SNAP? * * XXX - the header is actually variable-length. * Some various Linux patched versions gave 38 * as "off_linktype" and 40 as "off_nl"; however, * if a token ring packet has *no* routing * information, i.e. is not source-routed, the correct * values are 20 and 22, as they are in the vanilla code. * * A packet is source-routed iff the uppermost bit * of the first byte of the source address, at an * offset of 8, has the uppermost bit set. If the * packet is source-routed, the total number of bytes * of routing information is 2 plus bits 0x1F00 of * the 16-bit value at an offset of 14 (shifted right * 8 - figure out which byte that is). */ cstate->off_linktype.constant_part = 14; cstate->off_linkpl.constant_part = 14; /* Token Ring MAC header length */ cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: cstate->off_linkhdr.is_variable = 1; /* Fall through, 802.11 doesn't have a variable link * prefix but is otherwise the same. */ case DLT_IEEE802_11: /* * 802.11 doesn't really have a link-level type field. * We set "off_linktype.constant_part" to the offset of * the LLC header. * * To check for Ethernet types, we assume that SSAP = SNAP * is being used and pick out the encapsulated Ethernet type. * XXX - should we generate code to check for SNAP? * * We also handle variable-length radio headers here. * The Prism header is in theory variable-length, but in * practice it's always 144 bytes long. However, some * drivers on Linux use ARPHRD_IEEE80211_PRISM, but * sometimes or always supply an AVS header, so we * have to check whether the radio header is a Prism * header or an AVS header, so, in practice, it's * variable-length. */ cstate->off_linktype.constant_part = 24; cstate->off_linkpl.constant_part = 0; /* link-layer header is variable-length */ cstate->off_linkpl.is_variable = 1; cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_PPI: /* * At the moment we treat PPI the same way that we treat * normal Radiotap encoded packets. The difference is in * the function that generates the code at the beginning * to compute the header length. Since this code generator * of PPI supports bare 802.11 encapsulation only (i.e. * the encapsulated DLT should be DLT_IEEE802_11) we * generate code to check for this too. */ cstate->off_linktype.constant_part = 24; cstate->off_linkpl.constant_part = 0; /* link-layer header is variable-length */ cstate->off_linkpl.is_variable = 1; cstate->off_linkhdr.is_variable = 1; cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_ATM_RFC1483: case DLT_ATM_CLIP: /* Linux ATM defines this */ /* * assume routed, non-ISO PDUs * (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00) * * XXX - what about ISO PDUs, e.g. CLNP, ISIS, ESIS, * or PPP with the PPP NLPID (e.g., PPPoA)? The * latter would presumably be treated the way PPPoE * should be, so you can do "pppoe and udp port 2049" * or "pppoa and tcp port 80" and have it check for * PPPo{A,E} and a PPP protocol of IP and.... */ cstate->off_linktype.constant_part = 0; cstate->off_linkpl.constant_part = 0; /* packet begins with LLC header */ cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_SUNATM: /* * Full Frontal ATM; you get AALn PDUs with an ATM * pseudo-header. */ cstate->is_atm = 1; cstate->off_vpi = SUNATM_VPI_POS; cstate->off_vci = SUNATM_VCI_POS; cstate->off_proto = PROTO_POS; cstate->off_payload = SUNATM_PKT_BEGIN_POS; cstate->off_linktype.constant_part = cstate->off_payload; cstate->off_linkpl.constant_part = cstate->off_payload; /* if LLC-encapsulated */ cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_RAW: case DLT_IPV4: case DLT_IPV6: cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = 0; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_LINUX_SLL: /* fake header for Linux cooked socket */ cstate->off_linktype.constant_part = 14; cstate->off_linkpl.constant_part = 16; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_LTALK: /* * LocalTalk does have a 1-byte type field in the LLAP header, * but really it just indicates whether there is a "short" or * "long" DDP packet following. */ cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = 0; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_IP_OVER_FC: /* * RFC 2625 IP-over-Fibre-Channel doesn't really have a * link-level type field. We set "off_linktype" to the * offset of the LLC header. * * To check for Ethernet types, we assume that SSAP = SNAP * is being used and pick out the encapsulated Ethernet type. * XXX - should we generate code to check for SNAP? RFC * 2625 says SNAP should be used. */ cstate->off_linktype.constant_part = 16; cstate->off_linkpl.constant_part = 16; cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_FRELAY: /* * XXX - we should set this to handle SNAP-encapsulated * frames (NLPID of 0x80). */ cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = 0; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; /* * the only BPF-interesting FRF.16 frames are non-control frames; * Frame Relay has a variable length link-layer * so lets start with offset 4 for now and increments later on (FIXME); */ case DLT_MFR: cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = 0; cstate->off_nl = 4; cstate->off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */ break; case DLT_APPLE_IP_OVER_IEEE1394: cstate->off_linktype.constant_part = 16; cstate->off_linkpl.constant_part = 18; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_SYMANTEC_FIREWALL: cstate->off_linktype.constant_part = 6; cstate->off_linkpl.constant_part = 44; cstate->off_nl = 0; /* Ethernet II */ cstate->off_nl_nosnap = 0; /* XXX - what does it do with 802.3 packets? */ break; #ifdef HAVE_NET_PFVAR_H case DLT_PFLOG: cstate->off_linktype.constant_part = 0; cstate->off_linkpl.constant_part = PFLOG_HDRLEN; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; #endif case DLT_JUNIPER_MFR: case DLT_JUNIPER_MLFR: case DLT_JUNIPER_MLPPP: case DLT_JUNIPER_PPP: case DLT_JUNIPER_CHDLC: case DLT_JUNIPER_FRELAY: cstate->off_linktype.constant_part = 4; cstate->off_linkpl.constant_part = 4; cstate->off_nl = 0; cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ break; case DLT_JUNIPER_ATM1: cstate->off_linktype.constant_part = 4; /* in reality variable between 4-8 */ cstate->off_linkpl.constant_part = 4; /* in reality variable between 4-8 */ cstate->off_nl = 0; cstate->off_nl_nosnap = 10; break; case DLT_JUNIPER_ATM2: cstate->off_linktype.constant_part = 8; /* in reality variable between 8-12 */ cstate->off_linkpl.constant_part = 8; /* in reality variable between 8-12 */ cstate->off_nl = 0; cstate->off_nl_nosnap = 10; break; /* frames captured on a Juniper PPPoE service PIC * contain raw ethernet frames */ case DLT_JUNIPER_PPPOE: case DLT_JUNIPER_ETHER: cstate->off_linkpl.constant_part = 14; cstate->off_linktype.constant_part = 16; cstate->off_nl = 18; /* Ethernet II */ cstate->off_nl_nosnap = 21; /* 802.3+802.2 */ break; case DLT_JUNIPER_PPPOE_ATM: cstate->off_linktype.constant_part = 4; cstate->off_linkpl.constant_part = 6; cstate->off_nl = 0; cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ break; case DLT_JUNIPER_GGSN: cstate->off_linktype.constant_part = 6; cstate->off_linkpl.constant_part = 12; cstate->off_nl = 0; cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ break; case DLT_JUNIPER_ES: cstate->off_linktype.constant_part = 6; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* not really a network layer but raw IP addresses */ cstate->off_nl = -1; /* not really a network layer but raw IP addresses */ cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ break; case DLT_JUNIPER_MONITOR: cstate->off_linktype.constant_part = 12; cstate->off_linkpl.constant_part = 12; cstate->off_nl = 0; /* raw IP/IP6 header */ cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ break; case DLT_BACNET_MS_TP: cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = -1; cstate->off_nl_nosnap = -1; break; case DLT_JUNIPER_SERVICES: cstate->off_linktype.constant_part = 12; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* L3 proto location dep. on cookie type */ cstate->off_nl = -1; /* L3 proto location dep. on cookie type */ cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ break; case DLT_JUNIPER_VP: cstate->off_linktype.constant_part = 18; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = -1; cstate->off_nl_nosnap = -1; break; case DLT_JUNIPER_ST: cstate->off_linktype.constant_part = 18; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = -1; cstate->off_nl_nosnap = -1; break; case DLT_JUNIPER_ISM: cstate->off_linktype.constant_part = 8; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = -1; cstate->off_nl_nosnap = -1; break; case DLT_JUNIPER_VS: case DLT_JUNIPER_SRX_E2E: case DLT_JUNIPER_FIBRECHANNEL: case DLT_JUNIPER_ATM_CEMIC: cstate->off_linktype.constant_part = 8; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = -1; cstate->off_nl_nosnap = -1; break; case DLT_MTP2: cstate->off_li = 2; cstate->off_li_hsl = 4; cstate->off_sio = 3; cstate->off_opc = 4; cstate->off_dpc = 4; cstate->off_sls = 7; cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = -1; cstate->off_nl_nosnap = -1; break; case DLT_MTP2_WITH_PHDR: cstate->off_li = 6; cstate->off_li_hsl = 8; cstate->off_sio = 7; cstate->off_opc = 8; cstate->off_dpc = 8; cstate->off_sls = 11; cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = -1; cstate->off_nl_nosnap = -1; break; case DLT_ERF: cstate->off_li = 22; cstate->off_li_hsl = 24; cstate->off_sio = 23; cstate->off_opc = 24; cstate->off_dpc = 24; cstate->off_sls = 27; cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = -1; cstate->off_nl_nosnap = -1; break; case DLT_PFSYNC: cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = 4; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; break; case DLT_AX25_KISS: /* * Currently, only raw "link[N:M]" filtering is supported. */ cstate->off_linktype.constant_part = OFFSET_NOT_SET; /* variable, min 15, max 71 steps of 7 */ cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = -1; /* variable, min 16, max 71 steps of 7 */ cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ break; case DLT_IPNET: cstate->off_linktype.constant_part = 1; cstate->off_linkpl.constant_part = 24; /* ipnet header length */ cstate->off_nl = 0; cstate->off_nl_nosnap = -1; break; case DLT_NETANALYZER: cstate->off_linkhdr.constant_part = 4; /* Ethernet header is past 4-byte pseudo-header */ cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12; cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* pseudo-header+Ethernet header length */ cstate->off_nl = 0; /* Ethernet II */ cstate->off_nl_nosnap = 3; /* 802.3+802.2 */ break; case DLT_NETANALYZER_TRANSPARENT: cstate->off_linkhdr.constant_part = 12; /* MAC header is past 4-byte pseudo-header, preamble, and SFD */ cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12; cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* pseudo-header+preamble+SFD+Ethernet header length */ cstate->off_nl = 0; /* Ethernet II */ cstate->off_nl_nosnap = 3; /* 802.3+802.2 */ break; default: /* * For values in the range in which we've assigned new * DLT_ values, only raw "link[N:M]" filtering is supported. */ if (cstate->linktype >= DLT_MATCHING_MIN && cstate->linktype <= DLT_MATCHING_MAX) { cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = -1; cstate->off_nl_nosnap = -1; } else { bpf_error(cstate, "unknown data link type %d", cstate->linktype); } break; } cstate->off_outermostlinkhdr = cstate->off_prevlinkhdr = cstate->off_linkhdr; } /* * Load a value relative to the specified absolute offset. */ static struct slist * gen_load_absoffsetrel(compiler_state_t *cstate, bpf_abs_offset *abs_offset, u_int offset, u_int size) { struct slist *s, *s2; s = gen_abs_offset_varpart(cstate, abs_offset); /* * If "s" is non-null, it has code to arrange that the X register * contains the variable part of the absolute offset, so we * generate a load relative to that, with an offset of * abs_offset->constant_part + offset. * * Otherwise, we can do an absolute load with an offset of * abs_offset->constant_part + offset. */ if (s != NULL) { /* * "s" points to a list of statements that puts the * variable part of the absolute offset into the X register. * Do an indirect load, to use the X register as an offset. */ s2 = new_stmt(cstate, BPF_LD|BPF_IND|size); s2->s.k = abs_offset->constant_part + offset; sappend(s, s2); } else { /* * There is no variable part of the absolute offset, so * just do an absolute load. */ s = new_stmt(cstate, BPF_LD|BPF_ABS|size); s->s.k = abs_offset->constant_part + offset; } return s; } /* * Load a value relative to the beginning of the specified header. */ static struct slist * gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size) { struct slist *s, *s2; switch (offrel) { case OR_PACKET: s = new_stmt(cstate, BPF_LD|BPF_ABS|size); s->s.k = offset; break; case OR_LINKHDR: s = gen_load_absoffsetrel(cstate, &cstate->off_linkhdr, offset, size); break; case OR_PREVLINKHDR: s = gen_load_absoffsetrel(cstate, &cstate->off_prevlinkhdr, offset, size); break; case OR_LLC: s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, offset, size); break; case OR_PREVMPLSHDR: s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl - 4 + offset, size); break; case OR_LINKPL: s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + offset, size); break; case OR_LINKPL_NOSNAP: s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl_nosnap + offset, size); break; case OR_LINKTYPE: s = gen_load_absoffsetrel(cstate, &cstate->off_linktype, offset, size); break; case OR_TRAN_IPV4: /* * Load the X register with the length of the IPv4 header * (plus the offset of the link-layer header, if it's * preceded by a variable-length header such as a radio * header), in bytes. */ s = gen_loadx_iphdrlen(cstate); /* * Load the item at {offset of the link-layer payload} + * {offset, relative to the start of the link-layer * paylod, of the IPv4 header} + {length of the IPv4 header} + * {specified offset}. * * If the offset of the link-layer payload is variable, * the variable part of that offset is included in the * value in the X register, and we include the constant * part in the offset of the load. */ s2 = new_stmt(cstate, BPF_LD|BPF_IND|size); s2->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + offset; sappend(s, s2); break; case OR_TRAN_IPV6: s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + 40 + offset, size); break; default: abort(); return NULL; } return s; } /* * Generate code to load into the X register the sum of the length of * the IPv4 header and the variable part of the offset of the link-layer * payload. */ static struct slist * gen_loadx_iphdrlen(compiler_state_t *cstate) { struct slist *s, *s2; s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); if (s != NULL) { /* * The offset of the link-layer payload has a variable * part. "s" points to a list of statements that put * the variable part of that offset into the X register. * * The 4*([k]&0xf) addressing mode can't be used, as we * don't have a constant offset, so we have to load the * value in question into the A register and add to it * the value from the X register. */ s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s2->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; sappend(s, s2); s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); s2->s.k = 0xf; sappend(s, s2); s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K); s2->s.k = 2; sappend(s, s2); /* * The A register now contains the length of the IP header. * We need to add to it the variable part of the offset of * the link-layer payload, which is still in the X * register, and move the result into the X register. */ sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); } else { /* * The offset of the link-layer payload is a constant, * so no code was generated to load the (non-existent) * variable part of that offset. * * This means we can use the 4*([k]&0xf) addressing * mode. Load the length of the IPv4 header, which * is at an offset of cstate->off_nl from the beginning of * the link-layer payload, and thus at an offset of * cstate->off_linkpl.constant_part + cstate->off_nl from the beginning * of the raw packet data, using that addressing mode. */ s = new_stmt(cstate, BPF_LDX|BPF_MSH|BPF_B); s->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; } return s; } static struct block * gen_uncond(compiler_state_t *cstate, int rsense) { struct block *b; struct slist *s; s = new_stmt(cstate, BPF_LD|BPF_IMM); s->s.k = !rsense; b = new_block(cstate, JMP(BPF_JEQ)); b->stmts = s; return b; } static inline struct block * gen_true(compiler_state_t *cstate) { return gen_uncond(cstate, 1); } static inline struct block * gen_false(compiler_state_t *cstate) { return gen_uncond(cstate, 0); } /* * Byte-swap a 32-bit number. * ("htonl()" or "ntohl()" won't work - we want to byte-swap even on * big-endian platforms.) */ #define SWAPLONG(y) \ ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) /* * Generate code to match a particular packet type. * * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP * value, if <= ETHERMTU. We use that to determine whether to * match the type/length field or to check the type/length field for * a value <= ETHERMTU to see whether it's a type field and then do * the appropriate test. */ static struct block * gen_ether_linktype(compiler_state_t *cstate, int proto) { struct block *b0, *b1; switch (proto) { case LLCSAP_ISONS: case LLCSAP_IP: case LLCSAP_NETBEUI: /* * OSI protocols and NetBEUI always use 802.2 encapsulation, * so we check the DSAP and SSAP. * * LLCSAP_IP checks for IP-over-802.2, rather * than IP-over-Ethernet or IP-over-SNAP. * * XXX - should we check both the DSAP and the * SSAP, like this, or should we check just the * DSAP, as we do for other types <= ETHERMTU * (i.e., other SAP values)? */ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32) ((proto << 8) | proto)); gen_and(b0, b1); return b1; case LLCSAP_IPX: /* * Check for; * * Ethernet_II frames, which are Ethernet * frames with a frame type of ETHERTYPE_IPX; * * Ethernet_802.3 frames, which are 802.3 * frames (i.e., the type/length field is * a length field, <= ETHERMTU, rather than * a type field) with the first two bytes * after the Ethernet/802.3 header being * 0xFFFF; * * Ethernet_802.2 frames, which are 802.3 * frames with an 802.2 LLC header and * with the IPX LSAP as the DSAP in the LLC * header; * * Ethernet_SNAP frames, which are 802.3 * frames with an LLC header and a SNAP * header and with an OUI of 0x000000 * (encapsulated Ethernet) and a protocol * ID of ETHERTYPE_IPX in the SNAP header. * * XXX - should we generate the same code both * for tests for LLCSAP_IPX and for ETHERTYPE_IPX? */ /* * This generates code to check both for the * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3. */ b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX); b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)0xFFFF); gen_or(b0, b1); /* * Now we add code to check for SNAP frames with * ETHERTYPE_IPX, i.e. Ethernet_SNAP. */ b0 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX); gen_or(b0, b1); /* * Now we generate code to check for 802.3 * frames in general. */ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); /* * Now add the check for 802.3 frames before the * check for Ethernet_802.2 and Ethernet_802.3, * as those checks should only be done on 802.3 * frames, not on Ethernet frames. */ gen_and(b0, b1); /* * Now add the check for Ethernet_II frames, and * do that before checking for the other frame * types. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX); gen_or(b0, b1); return b1; case ETHERTYPE_ATALK: case ETHERTYPE_AARP: /* * EtherTalk (AppleTalk protocols on Ethernet link * layer) may use 802.2 encapsulation. */ /* * Check for 802.2 encapsulation (EtherTalk phase 2?); * we check for an Ethernet type field less than * 1500, which means it's an 802.3 length field. */ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); /* * 802.2-encapsulated ETHERTYPE_ATALK packets are * SNAP packets with an organization code of * 0x080007 (Apple, for Appletalk) and a protocol * type of ETHERTYPE_ATALK (Appletalk). * * 802.2-encapsulated ETHERTYPE_AARP packets are * SNAP packets with an organization code of * 0x000000 (encapsulated Ethernet) and a protocol * type of ETHERTYPE_AARP (Appletalk ARP). */ if (proto == ETHERTYPE_ATALK) b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK); else /* proto == ETHERTYPE_AARP */ b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP); gen_and(b0, b1); /* * Check for Ethernet encapsulation (Ethertalk * phase 1?); we just check for the Ethernet * protocol type. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); gen_or(b0, b1); return b1; default: if (proto <= ETHERMTU) { /* * This is an LLC SAP value, so the frames * that match would be 802.2 frames. * Check that the frame is an 802.2 frame * (i.e., that the length/type field is * a length field, <= ETHERMTU) and * then check the DSAP. */ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); b1 = gen_cmp(cstate, OR_LINKTYPE, 2, BPF_B, (bpf_int32)proto); gen_and(b0, b1); return b1; } else { /* * This is an Ethernet type, so compare * the length/type field with it (if * the frame is an 802.2 frame, the length * field will be <= ETHERMTU, and, as * "proto" is > ETHERMTU, this test * will fail and the frame won't match, * which is what we want). */ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); } } } static struct block * gen_loopback_linktype(compiler_state_t *cstate, int proto) { /* * For DLT_NULL, the link-layer header is a 32-bit word * containing an AF_ value in *host* byte order, and for * DLT_ENC, the link-layer header begins with a 32-bit * word containing an AF_ value in host byte order. * * In addition, if we're reading a saved capture file, * the host byte order in the capture may not be the * same as the host byte order on this machine. * * For DLT_LOOP, the link-layer header is a 32-bit * word containing an AF_ value in *network* byte order. */ if (cstate->linktype == DLT_NULL || cstate->linktype == DLT_ENC) { /* * The AF_ value is in host byte order, but the BPF * interpreter will convert it to network byte order. * * If this is a save file, and it's from a machine * with the opposite byte order to ours, we byte-swap * the AF_ value. * * Then we run it through "htonl()", and generate * code to compare against the result. */ if (cstate->bpf_pcap->rfile != NULL && cstate->bpf_pcap->swapped) proto = SWAPLONG(proto); proto = htonl(proto); } return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, (bpf_int32)proto)); } /* * "proto" is an Ethernet type value and for IPNET, if it is not IPv4 * or IPv6 then we have an error. */ static struct block * gen_ipnet_linktype(compiler_state_t *cstate, int proto) { switch (proto) { case ETHERTYPE_IP: return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)IPH_AF_INET); /* NOTREACHED */ case ETHERTYPE_IPV6: return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)IPH_AF_INET6); /* NOTREACHED */ default: break; } return gen_false(cstate); } /* * Generate code to match a particular packet type. * * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP * value, if <= ETHERMTU. We use that to determine whether to * match the type field or to check the type field for the special * LINUX_SLL_P_802_2 value and then do the appropriate test. */ static struct block * gen_linux_sll_linktype(compiler_state_t *cstate, int proto) { struct block *b0, *b1; switch (proto) { case LLCSAP_ISONS: case LLCSAP_IP: case LLCSAP_NETBEUI: /* * OSI protocols and NetBEUI always use 802.2 encapsulation, * so we check the DSAP and SSAP. * * LLCSAP_IP checks for IP-over-802.2, rather * than IP-over-Ethernet or IP-over-SNAP. * * XXX - should we check both the DSAP and the * SSAP, like this, or should we check just the * DSAP, as we do for other types <= ETHERMTU * (i.e., other SAP values)? */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32) ((proto << 8) | proto)); gen_and(b0, b1); return b1; case LLCSAP_IPX: /* * Ethernet_II frames, which are Ethernet * frames with a frame type of ETHERTYPE_IPX; * * Ethernet_802.3 frames, which have a frame * type of LINUX_SLL_P_802_3; * * Ethernet_802.2 frames, which are 802.3 * frames with an 802.2 LLC header (i.e, have * a frame type of LINUX_SLL_P_802_2) and * with the IPX LSAP as the DSAP in the LLC * header; * * Ethernet_SNAP frames, which are 802.3 * frames with an LLC header and a SNAP * header and with an OUI of 0x000000 * (encapsulated Ethernet) and a protocol * ID of ETHERTYPE_IPX in the SNAP header. * * First, do the checks on LINUX_SLL_P_802_2 * frames; generate the check for either * Ethernet_802.2 or Ethernet_SNAP frames, and * then put a check for LINUX_SLL_P_802_2 frames * before it. */ b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX); b1 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX); gen_or(b0, b1); b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); gen_and(b0, b1); /* * Now check for 802.3 frames and OR that with * the previous test. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_3); gen_or(b0, b1); /* * Now add the check for Ethernet_II frames, and * do that before checking for the other frame * types. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX); gen_or(b0, b1); return b1; case ETHERTYPE_ATALK: case ETHERTYPE_AARP: /* * EtherTalk (AppleTalk protocols on Ethernet link * layer) may use 802.2 encapsulation. */ /* * Check for 802.2 encapsulation (EtherTalk phase 2?); * we check for the 802.2 protocol type in the * "Ethernet type" field. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); /* * 802.2-encapsulated ETHERTYPE_ATALK packets are * SNAP packets with an organization code of * 0x080007 (Apple, for Appletalk) and a protocol * type of ETHERTYPE_ATALK (Appletalk). * * 802.2-encapsulated ETHERTYPE_AARP packets are * SNAP packets with an organization code of * 0x000000 (encapsulated Ethernet) and a protocol * type of ETHERTYPE_AARP (Appletalk ARP). */ if (proto == ETHERTYPE_ATALK) b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK); else /* proto == ETHERTYPE_AARP */ b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP); gen_and(b0, b1); /* * Check for Ethernet encapsulation (Ethertalk * phase 1?); we just check for the Ethernet * protocol type. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); gen_or(b0, b1); return b1; default: if (proto <= ETHERMTU) { /* * This is an LLC SAP value, so the frames * that match would be 802.2 frames. * Check for the 802.2 protocol type * in the "Ethernet type" field, and * then check the DSAP. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); b1 = gen_cmp(cstate, OR_LINKHDR, cstate->off_linkpl.constant_part, BPF_B, (bpf_int32)proto); gen_and(b0, b1); return b1; } else { /* * This is an Ethernet type, so compare * the length/type field with it (if * the frame is an 802.2 frame, the length * field will be <= ETHERMTU, and, as * "proto" is > ETHERMTU, this test * will fail and the frame won't match, * which is what we want). */ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); } } } static struct slist * gen_load_prism_llprefixlen(compiler_state_t *cstate) { struct slist *s1, *s2; struct slist *sjeq_avs_cookie; struct slist *sjcommon; /* * This code is not compatible with the optimizer, as * we are generating jmp instructions within a normal * slist of instructions */ cstate->no_optimize = 1; /* * Generate code to load the length of the radio header into * the register assigned to hold that length, if one has been * assigned. (If one hasn't been assigned, no code we've * generated uses that prefix, so we don't need to generate any * code to load it.) * * Some Linux drivers use ARPHRD_IEEE80211_PRISM but sometimes * or always use the AVS header rather than the Prism header. * We load a 4-byte big-endian value at the beginning of the * raw packet data, and see whether, when masked with 0xFFFFF000, * it's equal to 0x80211000. If so, that indicates that it's * an AVS header (the masked-out bits are the version number). * Otherwise, it's a Prism header. * * XXX - the Prism header is also, in theory, variable-length, * but no known software generates headers that aren't 144 * bytes long. */ if (cstate->off_linkhdr.reg != -1) { /* * Load the cookie. */ s1 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); s1->s.k = 0; /* * AND it with 0xFFFFF000. */ s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); s2->s.k = 0xFFFFF000; sappend(s1, s2); /* * Compare with 0x80211000. */ sjeq_avs_cookie = new_stmt(cstate, JMP(BPF_JEQ)); sjeq_avs_cookie->s.k = 0x80211000; sappend(s1, sjeq_avs_cookie); /* * If it's AVS: * * The 4 bytes at an offset of 4 from the beginning of * the AVS header are the length of the AVS header. * That field is big-endian. */ s2 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); s2->s.k = 4; sappend(s1, s2); sjeq_avs_cookie->s.jt = s2; /* * Now jump to the code to allocate a register * into which to save the header length and * store the length there. (The "jump always" * instruction needs to have the k field set; * it's added to the PC, so, as we're jumping * over a single instruction, it should be 1.) */ sjcommon = new_stmt(cstate, JMP(BPF_JA)); sjcommon->s.k = 1; sappend(s1, sjcommon); /* * Now for the code that handles the Prism header. * Just load the length of the Prism header (144) * into the A register. Have the test for an AVS * header branch here if we don't have an AVS header. */ s2 = new_stmt(cstate, BPF_LD|BPF_W|BPF_IMM); s2->s.k = 144; sappend(s1, s2); sjeq_avs_cookie->s.jf = s2; /* * Now allocate a register to hold that value and store * it. The code for the AVS header will jump here after * loading the length of the AVS header. */ s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkhdr.reg; sappend(s1, s2); sjcommon->s.jf = s2; /* * Now move it into the X register. */ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); } else return (NULL); } static struct slist * gen_load_avs_llprefixlen(compiler_state_t *cstate) { struct slist *s1, *s2; /* * Generate code to load the length of the AVS header into * the register assigned to hold that length, if one has been * assigned. (If one hasn't been assigned, no code we've * generated uses that prefix, so we don't need to generate any * code to load it.) */ if (cstate->off_linkhdr.reg != -1) { /* * The 4 bytes at an offset of 4 from the beginning of * the AVS header are the length of the AVS header. * That field is big-endian. */ s1 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); s1->s.k = 4; /* * Now allocate a register to hold that value and store * it. */ s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkhdr.reg; sappend(s1, s2); /* * Now move it into the X register. */ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); } else return (NULL); } static struct slist * gen_load_radiotap_llprefixlen(compiler_state_t *cstate) { struct slist *s1, *s2; /* * Generate code to load the length of the radiotap header into * the register assigned to hold that length, if one has been * assigned. (If one hasn't been assigned, no code we've * generated uses that prefix, so we don't need to generate any * code to load it.) */ if (cstate->off_linkhdr.reg != -1) { /* * The 2 bytes at offsets of 2 and 3 from the beginning * of the radiotap header are the length of the radiotap * header; unfortunately, it's little-endian, so we have * to load it a byte at a time and construct the value. */ /* * Load the high-order byte, at an offset of 3, shift it * left a byte, and put the result in the X register. */ s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); s1->s.k = 3; s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K); sappend(s1, s2); s2->s.k = 8; s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); /* * Load the next byte, at an offset of 2, and OR the * value from the X register into it. */ s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); sappend(s1, s2); s2->s.k = 2; s2 = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_X); sappend(s1, s2); /* * Now allocate a register to hold that value and store * it. */ s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkhdr.reg; sappend(s1, s2); /* * Now move it into the X register. */ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); } else return (NULL); } /* * At the moment we treat PPI as normal Radiotap encoded * packets. The difference is in the function that generates * the code at the beginning to compute the header length. * Since this code generator of PPI supports bare 802.11 * encapsulation only (i.e. the encapsulated DLT should be * DLT_IEEE802_11) we generate code to check for this too; * that's done in finish_parse(). */ static struct slist * gen_load_ppi_llprefixlen(compiler_state_t *cstate) { struct slist *s1, *s2; /* * Generate code to load the length of the radiotap header * into the register assigned to hold that length, if one has * been assigned. */ if (cstate->off_linkhdr.reg != -1) { /* * The 2 bytes at offsets of 2 and 3 from the beginning * of the radiotap header are the length of the radiotap * header; unfortunately, it's little-endian, so we have * to load it a byte at a time and construct the value. */ /* * Load the high-order byte, at an offset of 3, shift it * left a byte, and put the result in the X register. */ s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); s1->s.k = 3; s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K); sappend(s1, s2); s2->s.k = 8; s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); /* * Load the next byte, at an offset of 2, and OR the * value from the X register into it. */ s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); sappend(s1, s2); s2->s.k = 2; s2 = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_X); sappend(s1, s2); /* * Now allocate a register to hold that value and store * it. */ s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkhdr.reg; sappend(s1, s2); /* * Now move it into the X register. */ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); } else return (NULL); } /* * Load a value relative to the beginning of the link-layer header after the 802.11 * header, i.e. LLC_SNAP. * The link-layer header doesn't necessarily begin at the beginning * of the packet data; there might be a variable-length prefix containing * radio information. */ static struct slist * gen_load_802_11_header_len(compiler_state_t *cstate, struct slist *s, struct slist *snext) { struct slist *s2; struct slist *sjset_data_frame_1; struct slist *sjset_data_frame_2; struct slist *sjset_qos; struct slist *sjset_radiotap_flags_present; struct slist *sjset_radiotap_ext_present; struct slist *sjset_radiotap_tsft_present; struct slist *sjset_tsft_datapad, *sjset_notsft_datapad; struct slist *s_roundup; if (cstate->off_linkpl.reg == -1) { /* * No register has been assigned to the offset of * the link-layer payload, which means nobody needs * it; don't bother computing it - just return * what we already have. */ return (s); } /* * This code is not compatible with the optimizer, as * we are generating jmp instructions within a normal * slist of instructions */ cstate->no_optimize = 1; /* * If "s" is non-null, it has code to arrange that the X register * contains the length of the prefix preceding the link-layer * header. * * Otherwise, the length of the prefix preceding the link-layer * header is "off_outermostlinkhdr.constant_part". */ if (s == NULL) { /* * There is no variable-length header preceding the * link-layer header. * * Load the length of the fixed-length prefix preceding * the link-layer header (if any) into the X register, * and store it in the cstate->off_linkpl.reg register. * That length is off_outermostlinkhdr.constant_part. */ s = new_stmt(cstate, BPF_LDX|BPF_IMM); s->s.k = cstate->off_outermostlinkhdr.constant_part; } /* * The X register contains the offset of the beginning of the * link-layer header; add 24, which is the minimum length * of the MAC header for a data frame, to that, and store it * in cstate->off_linkpl.reg, and then load the Frame Control field, * which is at the offset in the X register, with an indexed load. */ s2 = new_stmt(cstate, BPF_MISC|BPF_TXA); sappend(s, s2); s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s2->s.k = 24; sappend(s, s2); s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkpl.reg; sappend(s, s2); s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s2->s.k = 0; sappend(s, s2); /* * Check the Frame Control field to see if this is a data frame; * a data frame has the 0x08 bit (b3) in that field set and the * 0x04 bit (b2) clear. */ sjset_data_frame_1 = new_stmt(cstate, JMP(BPF_JSET)); sjset_data_frame_1->s.k = 0x08; sappend(s, sjset_data_frame_1); /* * If b3 is set, test b2, otherwise go to the first statement of * the rest of the program. */ sjset_data_frame_1->s.jt = sjset_data_frame_2 = new_stmt(cstate, JMP(BPF_JSET)); sjset_data_frame_2->s.k = 0x04; sappend(s, sjset_data_frame_2); sjset_data_frame_1->s.jf = snext; /* * If b2 is not set, this is a data frame; test the QoS bit. * Otherwise, go to the first statement of the rest of the * program. */ sjset_data_frame_2->s.jt = snext; sjset_data_frame_2->s.jf = sjset_qos = new_stmt(cstate, JMP(BPF_JSET)); sjset_qos->s.k = 0x80; /* QoS bit */ sappend(s, sjset_qos); /* * If it's set, add 2 to cstate->off_linkpl.reg, to skip the QoS * field. * Otherwise, go to the first statement of the rest of the * program. */ sjset_qos->s.jt = s2 = new_stmt(cstate, BPF_LD|BPF_MEM); s2->s.k = cstate->off_linkpl.reg; sappend(s, s2); s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM); s2->s.k = 2; sappend(s, s2); s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkpl.reg; sappend(s, s2); /* * If we have a radiotap header, look at it to see whether * there's Atheros padding between the MAC-layer header * and the payload. * * Note: all of the fields in the radiotap header are * little-endian, so we byte-swap all of the values * we test against, as they will be loaded as big-endian * values. * * XXX - in the general case, we would have to scan through * *all* the presence bits, if there's more than one word of * presence bits. That would require a loop, meaning that * we wouldn't be able to run the filter in the kernel. * * We assume here that the Atheros adapters that insert the * annoying padding don't have multiple antennae and therefore * do not generate radiotap headers with multiple presence words. */ if (cstate->linktype == DLT_IEEE802_11_RADIO) { /* * Is the IEEE80211_RADIOTAP_FLAGS bit (0x0000002) set * in the first presence flag word? */ sjset_qos->s.jf = s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_W); s2->s.k = 4; sappend(s, s2); sjset_radiotap_flags_present = new_stmt(cstate, JMP(BPF_JSET)); sjset_radiotap_flags_present->s.k = SWAPLONG(0x00000002); sappend(s, sjset_radiotap_flags_present); /* * If not, skip all of this. */ sjset_radiotap_flags_present->s.jf = snext; /* * Otherwise, is the "extension" bit set in that word? */ sjset_radiotap_ext_present = new_stmt(cstate, JMP(BPF_JSET)); sjset_radiotap_ext_present->s.k = SWAPLONG(0x80000000); sappend(s, sjset_radiotap_ext_present); sjset_radiotap_flags_present->s.jt = sjset_radiotap_ext_present; /* * If so, skip all of this. */ sjset_radiotap_ext_present->s.jt = snext; /* * Otherwise, is the IEEE80211_RADIOTAP_TSFT bit set? */ sjset_radiotap_tsft_present = new_stmt(cstate, JMP(BPF_JSET)); sjset_radiotap_tsft_present->s.k = SWAPLONG(0x00000001); sappend(s, sjset_radiotap_tsft_present); sjset_radiotap_ext_present->s.jf = sjset_radiotap_tsft_present; /* * If IEEE80211_RADIOTAP_TSFT is set, the flags field is * at an offset of 16 from the beginning of the raw packet * data (8 bytes for the radiotap header and 8 bytes for * the TSFT field). * * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20) * is set. */ s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B); s2->s.k = 16; sappend(s, s2); sjset_radiotap_tsft_present->s.jt = s2; sjset_tsft_datapad = new_stmt(cstate, JMP(BPF_JSET)); sjset_tsft_datapad->s.k = 0x20; sappend(s, sjset_tsft_datapad); /* * If IEEE80211_RADIOTAP_TSFT is not set, the flags field is * at an offset of 8 from the beginning of the raw packet * data (8 bytes for the radiotap header). * * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20) * is set. */ s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B); s2->s.k = 8; sappend(s, s2); sjset_radiotap_tsft_present->s.jf = s2; sjset_notsft_datapad = new_stmt(cstate, JMP(BPF_JSET)); sjset_notsft_datapad->s.k = 0x20; sappend(s, sjset_notsft_datapad); /* * In either case, if IEEE80211_RADIOTAP_F_DATAPAD is * set, round the length of the 802.11 header to * a multiple of 4. Do that by adding 3 and then * dividing by and multiplying by 4, which we do by * ANDing with ~3. */ s_roundup = new_stmt(cstate, BPF_LD|BPF_MEM); s_roundup->s.k = cstate->off_linkpl.reg; sappend(s, s_roundup); s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM); s2->s.k = 3; sappend(s, s2); s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_IMM); s2->s.k = ~3; sappend(s, s2); s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkpl.reg; sappend(s, s2); sjset_tsft_datapad->s.jt = s_roundup; sjset_tsft_datapad->s.jf = snext; sjset_notsft_datapad->s.jt = s_roundup; sjset_notsft_datapad->s.jf = snext; } else sjset_qos->s.jf = snext; return s; } static void insert_compute_vloffsets(compiler_state_t *cstate, struct block *b) { struct slist *s; /* There is an implicit dependency between the link * payload and link header since the payload computation * includes the variable part of the header. Therefore, * if nobody else has allocated a register for the link * header and we need it, do it now. */ if (cstate->off_linkpl.reg != -1 && cstate->off_linkhdr.is_variable && cstate->off_linkhdr.reg == -1) cstate->off_linkhdr.reg = alloc_reg(cstate); /* * For link-layer types that have a variable-length header * preceding the link-layer header, generate code to load * the offset of the link-layer header into the register * assigned to that offset, if any. * * XXX - this, and the next switch statement, won't handle * encapsulation of 802.11 or 802.11+radio information in * some other protocol stack. That's significantly more * complicated. */ switch (cstate->outermostlinktype) { case DLT_PRISM_HEADER: s = gen_load_prism_llprefixlen(cstate); break; case DLT_IEEE802_11_RADIO_AVS: s = gen_load_avs_llprefixlen(cstate); break; case DLT_IEEE802_11_RADIO: s = gen_load_radiotap_llprefixlen(cstate); break; case DLT_PPI: s = gen_load_ppi_llprefixlen(cstate); break; default: s = NULL; break; } /* * For link-layer types that have a variable-length link-layer * header, generate code to load the offset of the link-layer * payload into the register assigned to that offset, if any. */ switch (cstate->outermostlinktype) { case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: s = gen_load_802_11_header_len(cstate, s, b->stmts); break; } /* * If we have any offset-loading code, append all the * existing statements in the block to those statements, * and make the resulting list the list of statements * for the block. */ if (s != NULL) { sappend(s, b->stmts); b->stmts = s; } } static struct block * gen_ppi_dlt_check(compiler_state_t *cstate) { struct slist *s_load_dlt; struct block *b; if (cstate->linktype == DLT_PPI) { /* Create the statements that check for the DLT */ s_load_dlt = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); s_load_dlt->s.k = 4; b = new_block(cstate, JMP(BPF_JEQ)); b->stmts = s_load_dlt; b->s.k = SWAPLONG(DLT_IEEE802_11); } else { b = NULL; } return b; } /* * Take an absolute offset, and: * * if it has no variable part, return NULL; * * if it has a variable part, generate code to load the register * containing that variable part into the X register, returning * a pointer to that code - if no register for that offset has * been allocated, allocate it first. * * (The code to set that register will be generated later, but will * be placed earlier in the code sequence.) */ static struct slist * gen_abs_offset_varpart(compiler_state_t *cstate, bpf_abs_offset *off) { struct slist *s; if (off->is_variable) { if (off->reg == -1) { /* * We haven't yet assigned a register for the * variable part of the offset of the link-layer * header; allocate one. */ off->reg = alloc_reg(cstate); } /* * Load the register containing the variable part of the * offset of the link-layer header into the X register. */ s = new_stmt(cstate, BPF_LDX|BPF_MEM); s->s.k = off->reg; return s; } else { /* * That offset isn't variable, there's no variable part, * so we don't need to generate any code. */ return NULL; } } /* * Map an Ethernet type to the equivalent PPP type. */ static int ethertype_to_ppptype(proto) int proto; { switch (proto) { case ETHERTYPE_IP: proto = PPP_IP; break; case ETHERTYPE_IPV6: proto = PPP_IPV6; break; case ETHERTYPE_DN: proto = PPP_DECNET; break; case ETHERTYPE_ATALK: proto = PPP_APPLE; break; case ETHERTYPE_NS: proto = PPP_NS; break; case LLCSAP_ISONS: proto = PPP_OSI; break; case LLCSAP_8021D: /* * I'm assuming the "Bridging PDU"s that go * over PPP are Spanning Tree Protocol * Bridging PDUs. */ proto = PPP_BRPDU; break; case LLCSAP_IPX: proto = PPP_IPX; break; } return (proto); } /* * Generate any tests that, for encapsulation of a link-layer packet * inside another protocol stack, need to be done to check for those * link-layer packets (and that haven't already been done by a check * for that encapsulation). */ static struct block * gen_prevlinkhdr_check(compiler_state_t *cstate) { struct block *b0; if (cstate->is_geneve) return gen_geneve_ll_check(cstate); switch (cstate->prevlinktype) { case DLT_SUNATM: /* * This is LANE-encapsulated Ethernet; check that the LANE * packet doesn't begin with an LE Control marker, i.e. * that it's data, not a control message. * * (We've already generated a test for LANE.) */ b0 = gen_cmp(cstate, OR_PREVLINKHDR, SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00); gen_not(b0); return b0; default: /* * No such tests are necessary. */ return NULL; } /*NOTREACHED*/ } /* * The three different values we should check for when checking for an * IPv6 packet with DLT_NULL. */ #define BSD_AFNUM_INET6_BSD 24 /* NetBSD, OpenBSD, BSD/OS, Npcap */ #define BSD_AFNUM_INET6_FREEBSD 28 /* FreeBSD */ #define BSD_AFNUM_INET6_DARWIN 30 /* OS X, iOS, other Darwin-based OSes */ /* * Generate code to match a particular packet type by matching the * link-layer type field or fields in the 802.2 LLC header. * * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP * value, if <= ETHERMTU. */ static struct block * gen_linktype(compiler_state_t *cstate, int proto) { struct block *b0, *b1, *b2; const char *description; /* are we checking MPLS-encapsulated packets? */ if (cstate->label_stack_depth > 0) { switch (proto) { case ETHERTYPE_IP: case PPP_IP: /* FIXME add other L3 proto IDs */ return gen_mpls_linktype(cstate, Q_IP); case ETHERTYPE_IPV6: case PPP_IPV6: /* FIXME add other L3 proto IDs */ return gen_mpls_linktype(cstate, Q_IPV6); default: bpf_error(cstate, "unsupported protocol over mpls"); /* NOTREACHED */ } } switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: /* Geneve has an EtherType regardless of whether there is an * L2 header. */ if (!cstate->is_geneve) b0 = gen_prevlinkhdr_check(cstate); else b0 = NULL; b1 = gen_ether_linktype(cstate, proto); if (b0 != NULL) gen_and(b0, b1); return b1; /*NOTREACHED*/ break; case DLT_C_HDLC: switch (proto) { case LLCSAP_ISONS: proto = (proto << 8 | LLCSAP_ISONS); /* fall through */ default: return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); /*NOTREACHED*/ break; } break; case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: /* * Check that we have a data frame. */ b0 = gen_check_802_11_data_frame(cstate); /* * Now check for the specified link-layer type. */ b1 = gen_llc_linktype(cstate, proto); gen_and(b0, b1); return b1; /*NOTREACHED*/ break; case DLT_FDDI: /* * XXX - check for LLC frames. */ return gen_llc_linktype(cstate, proto); /*NOTREACHED*/ break; case DLT_IEEE802: /* * XXX - check for LLC PDUs, as per IEEE 802.5. */ return gen_llc_linktype(cstate, proto); /*NOTREACHED*/ break; case DLT_ATM_RFC1483: case DLT_ATM_CLIP: case DLT_IP_OVER_FC: return gen_llc_linktype(cstate, proto); /*NOTREACHED*/ break; case DLT_SUNATM: /* * Check for an LLC-encapsulated version of this protocol; * if we were checking for LANE, linktype would no longer * be DLT_SUNATM. * * Check for LLC encapsulation and then check the protocol. */ b0 = gen_atmfield_code(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); b1 = gen_llc_linktype(cstate, proto); gen_and(b0, b1); return b1; /*NOTREACHED*/ break; case DLT_LINUX_SLL: return gen_linux_sll_linktype(cstate, proto); /*NOTREACHED*/ break; case DLT_SLIP: case DLT_SLIP_BSDOS: case DLT_RAW: /* * These types don't provide any type field; packets * are always IPv4 or IPv6. * * XXX - for IPv4, check for a version number of 4, and, * for IPv6, check for a version number of 6? */ switch (proto) { case ETHERTYPE_IP: /* Check for a version number of 4. */ return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, 0x40, 0xF0); case ETHERTYPE_IPV6: /* Check for a version number of 6. */ return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, 0x60, 0xF0); default: return gen_false(cstate); /* always false */ } /*NOTREACHED*/ break; case DLT_IPV4: /* * Raw IPv4, so no type field. */ if (proto == ETHERTYPE_IP) return gen_true(cstate); /* always true */ /* Checking for something other than IPv4; always false */ return gen_false(cstate); /*NOTREACHED*/ break; case DLT_IPV6: /* * Raw IPv6, so no type field. */ if (proto == ETHERTYPE_IPV6) return gen_true(cstate); /* always true */ /* Checking for something other than IPv6; always false */ return gen_false(cstate); /*NOTREACHED*/ break; case DLT_PPP: case DLT_PPP_PPPD: case DLT_PPP_SERIAL: case DLT_PPP_ETHER: /* * We use Ethernet protocol types inside libpcap; * map them to the corresponding PPP protocol types. */ proto = ethertype_to_ppptype(proto); return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); /*NOTREACHED*/ break; case DLT_PPP_BSDOS: /* * We use Ethernet protocol types inside libpcap; * map them to the corresponding PPP protocol types. */ switch (proto) { case ETHERTYPE_IP: /* * Also check for Van Jacobson-compressed IP. * XXX - do this for other forms of PPP? */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_IP); b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_VJC); gen_or(b0, b1); b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_VJNC); gen_or(b1, b0); return b0; default: proto = ethertype_to_ppptype(proto); return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); } /*NOTREACHED*/ break; case DLT_NULL: case DLT_LOOP: case DLT_ENC: switch (proto) { case ETHERTYPE_IP: return (gen_loopback_linktype(cstate, AF_INET)); case ETHERTYPE_IPV6: /* * AF_ values may, unfortunately, be platform- * dependent; AF_INET isn't, because everybody * used 4.2BSD's value, but AF_INET6 is, because * 4.2BSD didn't have a value for it (given that * IPv6 didn't exist back in the early 1980's), * and they all picked their own values. * * This means that, if we're reading from a * savefile, we need to check for all the * possible values. * * If we're doing a live capture, we only need * to check for this platform's value; however, * Npcap uses 24, which isn't Windows's AF_INET6 * value. (Given the multiple different values, * programs that read pcap files shouldn't be * checking for their platform's AF_INET6 value * anyway, they should check for all of the * possible values. and they might as well do * that even for live captures.) */ if (cstate->bpf_pcap->rfile != NULL) { /* * Savefile - check for all three * possible IPv6 values. */ b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_BSD); b1 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_FREEBSD); gen_or(b0, b1); b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_DARWIN); gen_or(b0, b1); return (b1); } else { /* * Live capture, so we only need to * check for the value used on this * platform. */ #ifdef _WIN32 /* * Npcap doesn't use Windows's AF_INET6, * as that collides with AF_IPX on * some BSDs (both have the value 23). * Instead, it uses 24. */ return (gen_loopback_linktype(cstate, 24)); #else /* _WIN32 */ #ifdef AF_INET6 return (gen_loopback_linktype(cstate, AF_INET6)); #else /* AF_INET6 */ /* * I guess this platform doesn't support * IPv6, so we just reject all packets. */ return gen_false(cstate); #endif /* AF_INET6 */ #endif /* _WIN32 */ } default: /* * Not a type on which we support filtering. * XXX - support those that have AF_ values * #defined on this platform, at least? */ return gen_false(cstate); } #ifdef HAVE_NET_PFVAR_H case DLT_PFLOG: /* * af field is host byte order in contrast to the rest of * the packet. */ if (proto == ETHERTYPE_IP) return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af), BPF_B, (bpf_int32)AF_INET)); else if (proto == ETHERTYPE_IPV6) return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af), BPF_B, (bpf_int32)AF_INET6)); else return gen_false(cstate); /*NOTREACHED*/ break; #endif /* HAVE_NET_PFVAR_H */ case DLT_ARCNET: case DLT_ARCNET_LINUX: /* * XXX should we check for first fragment if the protocol * uses PHDS? */ switch (proto) { default: return gen_false(cstate); case ETHERTYPE_IPV6: return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_INET6)); case ETHERTYPE_IP: b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_IP); b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_IP_OLD); gen_or(b0, b1); return (b1); case ETHERTYPE_ARP: b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_ARP); b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_ARP_OLD); gen_or(b0, b1); return (b1); case ETHERTYPE_REVARP: return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_REVARP)); case ETHERTYPE_ATALK: return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_ATALK)); } /*NOTREACHED*/ break; case DLT_LTALK: switch (proto) { case ETHERTYPE_ATALK: return gen_true(cstate); default: return gen_false(cstate); } /*NOTREACHED*/ break; case DLT_FRELAY: /* * XXX - assumes a 2-byte Frame Relay header with * DLCI and flags. What if the address is longer? */ switch (proto) { case ETHERTYPE_IP: /* * Check for the special NLPID for IP. */ return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0xcc); case ETHERTYPE_IPV6: /* * Check for the special NLPID for IPv6. */ return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0x8e); case LLCSAP_ISONS: /* * Check for several OSI protocols. * * Frame Relay packets typically have an OSI * NLPID at the beginning; we check for each * of them. * * What we check for is the NLPID and a frame * control field of UI, i.e. 0x03 followed * by the NLPID. */ b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO8473_CLNP); b1 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO9542_ESIS); b2 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO10589_ISIS); gen_or(b1, b2); gen_or(b0, b2); return b2; default: return gen_false(cstate); } /*NOTREACHED*/ break; case DLT_MFR: bpf_error(cstate, "Multi-link Frame Relay link-layer type filtering not implemented"); case DLT_JUNIPER_MFR: case DLT_JUNIPER_MLFR: case DLT_JUNIPER_MLPPP: case DLT_JUNIPER_ATM1: case DLT_JUNIPER_ATM2: case DLT_JUNIPER_PPPOE: case DLT_JUNIPER_PPPOE_ATM: case DLT_JUNIPER_GGSN: case DLT_JUNIPER_ES: case DLT_JUNIPER_MONITOR: case DLT_JUNIPER_SERVICES: case DLT_JUNIPER_ETHER: case DLT_JUNIPER_PPP: case DLT_JUNIPER_FRELAY: case DLT_JUNIPER_CHDLC: case DLT_JUNIPER_VP: case DLT_JUNIPER_ST: case DLT_JUNIPER_ISM: case DLT_JUNIPER_VS: case DLT_JUNIPER_SRX_E2E: case DLT_JUNIPER_FIBRECHANNEL: case DLT_JUNIPER_ATM_CEMIC: /* just lets verify the magic number for now - * on ATM we may have up to 6 different encapsulations on the wire * and need a lot of heuristics to figure out that the payload * might be; * * FIXME encapsulation specific BPF_ filters */ return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x4d474300, 0xffffff00); /* compare the magic number */ case DLT_BACNET_MS_TP: return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x55FF0000, 0xffff0000); case DLT_IPNET: return gen_ipnet_linktype(cstate, proto); case DLT_LINUX_IRDA: bpf_error(cstate, "IrDA link-layer type filtering not implemented"); case DLT_DOCSIS: bpf_error(cstate, "DOCSIS link-layer type filtering not implemented"); case DLT_MTP2: case DLT_MTP2_WITH_PHDR: bpf_error(cstate, "MTP2 link-layer type filtering not implemented"); case DLT_ERF: bpf_error(cstate, "ERF link-layer type filtering not implemented"); case DLT_PFSYNC: bpf_error(cstate, "PFSYNC link-layer type filtering not implemented"); case DLT_LINUX_LAPD: bpf_error(cstate, "LAPD link-layer type filtering not implemented"); case DLT_USB_FREEBSD: case DLT_USB_LINUX: case DLT_USB_LINUX_MMAPPED: case DLT_USBPCAP: bpf_error(cstate, "USB link-layer type filtering not implemented"); case DLT_BLUETOOTH_HCI_H4: case DLT_BLUETOOTH_HCI_H4_WITH_PHDR: bpf_error(cstate, "Bluetooth link-layer type filtering not implemented"); case DLT_CAN20B: case DLT_CAN_SOCKETCAN: bpf_error(cstate, "CAN link-layer type filtering not implemented"); case DLT_IEEE802_15_4: case DLT_IEEE802_15_4_LINUX: case DLT_IEEE802_15_4_NONASK_PHY: case DLT_IEEE802_15_4_NOFCS: bpf_error(cstate, "IEEE 802.15.4 link-layer type filtering not implemented"); case DLT_IEEE802_16_MAC_CPS_RADIO: bpf_error(cstate, "IEEE 802.16 link-layer type filtering not implemented"); case DLT_SITA: bpf_error(cstate, "SITA link-layer type filtering not implemented"); case DLT_RAIF1: bpf_error(cstate, "RAIF1 link-layer type filtering not implemented"); case DLT_IPMB: bpf_error(cstate, "IPMB link-layer type filtering not implemented"); case DLT_AX25_KISS: bpf_error(cstate, "AX.25 link-layer type filtering not implemented"); case DLT_NFLOG: /* Using the fixed-size NFLOG header it is possible to tell only * the address family of the packet, other meaningful data is * either missing or behind TLVs. */ bpf_error(cstate, "NFLOG link-layer type filtering not implemented"); default: /* * Does this link-layer header type have a field * indicating the type of the next protocol? If * so, off_linktype.constant_part will be the offset of that * field in the packet; if not, it will be OFFSET_NOT_SET. */ if (cstate->off_linktype.constant_part != OFFSET_NOT_SET) { /* * Yes; assume it's an Ethernet type. (If * it's not, it needs to be handled specially * above.) */ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); } else { /* * No; report an error. */ description = pcap_datalink_val_to_description(cstate->linktype); if (description != NULL) { bpf_error(cstate, "%s link-layer type filtering not implemented", description); } else { bpf_error(cstate, "DLT %u link-layer type filtering not implemented", cstate->linktype); } } break; } } /* * Check for an LLC SNAP packet with a given organization code and * protocol type; we check the entire contents of the 802.2 LLC and * snap headers, checking for DSAP and SSAP of SNAP and a control * field of 0x03 in the LLC header, and for the specified organization * code and protocol type in the SNAP header. */ static struct block * gen_snap(compiler_state_t *cstate, bpf_u_int32 orgcode, bpf_u_int32 ptype) { u_char snapblock[8]; snapblock[0] = LLCSAP_SNAP; /* DSAP = SNAP */ snapblock[1] = LLCSAP_SNAP; /* SSAP = SNAP */ snapblock[2] = 0x03; /* control = UI */ snapblock[3] = (orgcode >> 16); /* upper 8 bits of organization code */ snapblock[4] = (orgcode >> 8); /* middle 8 bits of organization code */ snapblock[5] = (orgcode >> 0); /* lower 8 bits of organization code */ snapblock[6] = (ptype >> 8); /* upper 8 bits of protocol type */ snapblock[7] = (ptype >> 0); /* lower 8 bits of protocol type */ return gen_bcmp(cstate, OR_LLC, 0, 8, snapblock); } /* * Generate code to match frames with an LLC header. */ struct block * gen_llc(compiler_state_t *cstate) { struct block *b0, *b1; switch (cstate->linktype) { case DLT_EN10MB: /* * We check for an Ethernet type field less than * 1500, which means it's an 802.3 length field. */ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); /* * Now check for the purported DSAP and SSAP not being * 0xFF, to rule out NetWare-over-802.3. */ b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)0xFFFF); gen_not(b1); gen_and(b0, b1); return b1; case DLT_SUNATM: /* * We check for LLC traffic. */ b0 = gen_atmtype_abbrev(cstate, A_LLC); return b0; case DLT_IEEE802: /* Token Ring */ /* * XXX - check for LLC frames. */ return gen_true(cstate); case DLT_FDDI: /* * XXX - check for LLC frames. */ return gen_true(cstate); case DLT_ATM_RFC1483: /* * For LLC encapsulation, these are defined to have an * 802.2 LLC header. * * For VC encapsulation, they don't, but there's no * way to check for that; the protocol used on the VC * is negotiated out of band. */ return gen_true(cstate); case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO: case DLT_IEEE802_11_RADIO_AVS: case DLT_PPI: /* * Check that we have a data frame. */ b0 = gen_check_802_11_data_frame(cstate); return b0; default: bpf_error(cstate, "'llc' not supported for linktype %d", cstate->linktype); /* NOTREACHED */ } } struct block * gen_llc_i(compiler_state_t *cstate) { struct block *b0, *b1; struct slist *s; /* * Check whether this is an LLC frame. */ b0 = gen_llc(cstate); /* * Load the control byte and test the low-order bit; it must * be clear for I frames. */ s = gen_load_a(cstate, OR_LLC, 2, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x01; b1->stmts = s; gen_not(b1); gen_and(b0, b1); return b1; } struct block * gen_llc_s(compiler_state_t *cstate) { struct block *b0, *b1; /* * Check whether this is an LLC frame. */ b0 = gen_llc(cstate); /* * Now compare the low-order 2 bit of the control byte against * the appropriate value for S frames. */ b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, LLC_S_FMT, 0x03); gen_and(b0, b1); return b1; } struct block * gen_llc_u(compiler_state_t *cstate) { struct block *b0, *b1; /* * Check whether this is an LLC frame. */ b0 = gen_llc(cstate); /* * Now compare the low-order 2 bit of the control byte against * the appropriate value for U frames. */ b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, LLC_U_FMT, 0x03); gen_and(b0, b1); return b1; } struct block * gen_llc_s_subtype(compiler_state_t *cstate, bpf_u_int32 subtype) { struct block *b0, *b1; /* * Check whether this is an LLC frame. */ b0 = gen_llc(cstate); /* * Now check for an S frame with the appropriate type. */ b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, subtype, LLC_S_CMD_MASK); gen_and(b0, b1); return b1; } struct block * gen_llc_u_subtype(compiler_state_t *cstate, bpf_u_int32 subtype) { struct block *b0, *b1; /* * Check whether this is an LLC frame. */ b0 = gen_llc(cstate); /* * Now check for a U frame with the appropriate type. */ b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, subtype, LLC_U_CMD_MASK); gen_and(b0, b1); return b1; } /* * Generate code to match a particular packet type, for link-layer types * using 802.2 LLC headers. * * This is *NOT* used for Ethernet; "gen_ether_linktype()" is used * for that - it handles the D/I/X Ethernet vs. 802.3+802.2 issues. * * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP * value, if <= ETHERMTU. We use that to determine whether to * match the DSAP or both DSAP and LSAP or to check the OUI and * protocol ID in a SNAP header. */ static struct block * gen_llc_linktype(compiler_state_t *cstate, int proto) { /* * XXX - handle token-ring variable-length header. */ switch (proto) { case LLCSAP_IP: case LLCSAP_ISONS: case LLCSAP_NETBEUI: /* * XXX - should we check both the DSAP and the * SSAP, like this, or should we check just the * DSAP, as we do for other SAP values? */ return gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_u_int32) ((proto << 8) | proto)); case LLCSAP_IPX: /* * XXX - are there ever SNAP frames for IPX on * non-Ethernet 802.x networks? */ return gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX); case ETHERTYPE_ATALK: /* * 802.2-encapsulated ETHERTYPE_ATALK packets are * SNAP packets with an organization code of * 0x080007 (Apple, for Appletalk) and a protocol * type of ETHERTYPE_ATALK (Appletalk). * * XXX - check for an organization code of * encapsulated Ethernet as well? */ return gen_snap(cstate, 0x080007, ETHERTYPE_ATALK); default: /* * XXX - we don't have to check for IPX 802.3 * here, but should we check for the IPX Ethertype? */ if (proto <= ETHERMTU) { /* * This is an LLC SAP value, so check * the DSAP. */ return gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)proto); } else { /* * This is an Ethernet type; we assume that it's * unlikely that it'll appear in the right place * at random, and therefore check only the * location that would hold the Ethernet type * in a SNAP frame with an organization code of * 0x000000 (encapsulated Ethernet). * * XXX - if we were to check for the SNAP DSAP and * LSAP, as per XXX, and were also to check for an * organization code of 0x000000 (encapsulated * Ethernet), we'd do * * return gen_snap(cstate, 0x000000, proto); * * here; for now, we don't, as per the above. * I don't know whether it's worth the extra CPU * time to do the right check or not. */ return gen_cmp(cstate, OR_LLC, 6, BPF_H, (bpf_int32)proto); } } } static struct block * gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, int dir, int proto, u_int src_off, u_int dst_off) { struct block *b0, *b1; u_int offset; switch (dir) { case Q_SRC: offset = src_off; break; case Q_DST: offset = dst_off; break; case Q_AND: b0 = gen_hostop(cstate, addr, mask, Q_SRC, proto, src_off, dst_off); b1 = gen_hostop(cstate, addr, mask, Q_DST, proto, src_off, dst_off); gen_and(b0, b1); return b1; case Q_OR: case Q_DEFAULT: b0 = gen_hostop(cstate, addr, mask, Q_SRC, proto, src_off, dst_off); b1 = gen_hostop(cstate, addr, mask, Q_DST, proto, src_off, dst_off); gen_or(b0, b1); return b1; default: abort(); } b0 = gen_linktype(cstate, proto); b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, (bpf_int32)addr, mask); gen_and(b0, b1); return b1; } #ifdef INET6 static struct block * gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr, struct in6_addr *mask, int dir, int proto, u_int src_off, u_int dst_off) { struct block *b0, *b1; u_int offset; u_int32_t *a, *m; switch (dir) { case Q_SRC: offset = src_off; break; case Q_DST: offset = dst_off; break; case Q_AND: b0 = gen_hostop6(cstate, addr, mask, Q_SRC, proto, src_off, dst_off); b1 = gen_hostop6(cstate, addr, mask, Q_DST, proto, src_off, dst_off); gen_and(b0, b1); return b1; case Q_OR: case Q_DEFAULT: b0 = gen_hostop6(cstate, addr, mask, Q_SRC, proto, src_off, dst_off); b1 = gen_hostop6(cstate, addr, mask, Q_DST, proto, src_off, dst_off); gen_or(b0, b1); return b1; default: abort(); } /* this order is important */ a = (u_int32_t *)addr; m = (u_int32_t *)mask; b1 = gen_mcmp(cstate, OR_LINKPL, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3])); b0 = gen_mcmp(cstate, OR_LINKPL, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2])); gen_and(b0, b1); b0 = gen_mcmp(cstate, OR_LINKPL, offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1])); gen_and(b0, b1); b0 = gen_mcmp(cstate, OR_LINKPL, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0])); gen_and(b0, b1); b0 = gen_linktype(cstate, proto); gen_and(b0, b1); return b1; } #endif static struct block * gen_ehostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { register struct block *b0, *b1; switch (dir) { case Q_SRC: return gen_bcmp(cstate, OR_LINKHDR, 6, 6, eaddr); case Q_DST: return gen_bcmp(cstate, OR_LINKHDR, 0, 6, eaddr); case Q_AND: b0 = gen_ehostop(cstate, eaddr, Q_SRC); b1 = gen_ehostop(cstate, eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_ehostop(cstate, eaddr, Q_SRC); b1 = gen_ehostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' is only supported on 802.11 with 802.11 headers"); break; case Q_ADDR2: bpf_error(cstate, "'addr2' is only supported on 802.11 with 802.11 headers"); break; case Q_ADDR3: bpf_error(cstate, "'addr3' is only supported on 802.11 with 802.11 headers"); break; case Q_ADDR4: bpf_error(cstate, "'addr4' is only supported on 802.11 with 802.11 headers"); break; case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11 with 802.11 headers"); break; case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11 with 802.11 headers"); break; } abort(); /* NOTREACHED */ } /* * Like gen_ehostop, but for DLT_FDDI */ static struct block * gen_fhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { struct block *b0, *b1; switch (dir) { case Q_SRC: return gen_bcmp(cstate, OR_LINKHDR, 6 + 1 + cstate->pcap_fddipad, 6, eaddr); case Q_DST: return gen_bcmp(cstate, OR_LINKHDR, 0 + 1 + cstate->pcap_fddipad, 6, eaddr); case Q_AND: b0 = gen_fhostop(cstate, eaddr, Q_SRC); b1 = gen_fhostop(cstate, eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_fhostop(cstate, eaddr, Q_SRC); b1 = gen_fhostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' is only supported on 802.11"); break; case Q_ADDR2: bpf_error(cstate, "'addr2' is only supported on 802.11"); break; case Q_ADDR3: bpf_error(cstate, "'addr3' is only supported on 802.11"); break; case Q_ADDR4: bpf_error(cstate, "'addr4' is only supported on 802.11"); break; case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11"); break; case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11"); break; } abort(); /* NOTREACHED */ } /* * Like gen_ehostop, but for DLT_IEEE802 (Token Ring) */ static struct block * gen_thostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { register struct block *b0, *b1; switch (dir) { case Q_SRC: return gen_bcmp(cstate, OR_LINKHDR, 8, 6, eaddr); case Q_DST: return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr); case Q_AND: b0 = gen_thostop(cstate, eaddr, Q_SRC); b1 = gen_thostop(cstate, eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_thostop(cstate, eaddr, Q_SRC); b1 = gen_thostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' is only supported on 802.11"); break; case Q_ADDR2: bpf_error(cstate, "'addr2' is only supported on 802.11"); break; case Q_ADDR3: bpf_error(cstate, "'addr3' is only supported on 802.11"); break; case Q_ADDR4: bpf_error(cstate, "'addr4' is only supported on 802.11"); break; case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11"); break; case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11"); break; } abort(); /* NOTREACHED */ } /* * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) and * various 802.11 + radio headers. */ static struct block * gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { register struct block *b0, *b1, *b2; register struct slist *s; #ifdef ENABLE_WLAN_FILTERING_PATCH /* * TODO GV 20070613 * We need to disable the optimizer because the optimizer is buggy * and wipes out some LD instructions generated by the below * code to validate the Frame Control bits */ cstate->no_optimize = 1; #endif /* ENABLE_WLAN_FILTERING_PATCH */ switch (dir) { case Q_SRC: /* * Oh, yuk. * * For control frames, there is no SA. * * For management frames, SA is at an * offset of 10 from the beginning of * the packet. * * For data frames, SA is at an offset * of 10 from the beginning of the packet * if From DS is clear, at an offset of * 16 from the beginning of the packet * if From DS is set and To DS is clear, * and an offset of 24 from the beginning * of the packet if From DS is set and To DS * is set. */ /* * Generate the tests to be done for data frames * with From DS set. * * First, check for To DS set, i.e. check "link[1] & 0x01". */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x01; /* To DS */ b1->stmts = s; /* * If To DS is set, the SA is at 24. */ b0 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr); gen_and(b1, b0); /* * Now, check for To DS not set, i.e. check * "!(link[1] & 0x01)". */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x01; /* To DS */ b2->stmts = s; gen_not(b2); /* * If To DS is not set, the SA is at 16. */ b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); gen_and(b2, b1); /* * Now OR together the last two checks. That gives * the complete set of checks for data frames with * From DS set. */ gen_or(b1, b0); /* * Now check for From DS being set, and AND that with * the ORed-together checks. */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x02; /* From DS */ b1->stmts = s; gen_and(b1, b0); /* * Now check for data frames with From DS not set. */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x02; /* From DS */ b2->stmts = s; gen_not(b2); /* * If From DS isn't set, the SA is at 10. */ b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); /* * Now OR together the checks for data frames with * From DS not set and for data frames with From DS * set; that gives the checks done for data frames. */ gen_or(b1, b0); /* * Now check for a data frame. * I.e, check "link[0] & 0x08". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; /* * AND that with the checks done for data frames. */ gen_and(b1, b0); /* * If the high-order bit of the type value is 0, this * is a management frame. * I.e, check "!(link[0] & 0x08)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x08; b2->stmts = s; gen_not(b2); /* * For management frames, the SA is at 10. */ b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); /* * OR that with the checks done for data frames. * That gives the checks done for management and * data frames. */ gen_or(b1, b0); /* * If the low-order bit of the type value is 1, * this is either a control frame or a frame * with a reserved type, and thus not a * frame with an SA. * * I.e., check "!(link[0] & 0x04)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x04; b1->stmts = s; gen_not(b1); /* * AND that with the checks for data and management * frames. */ gen_and(b1, b0); return b0; case Q_DST: /* * Oh, yuk. * * For control frames, there is no DA. * * For management frames, DA is at an * offset of 4 from the beginning of * the packet. * * For data frames, DA is at an offset * of 4 from the beginning of the packet * if To DS is clear and at an offset of * 16 from the beginning of the packet * if To DS is set. */ /* * Generate the tests to be done for data frames. * * First, check for To DS set, i.e. "link[1] & 0x01". */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x01; /* To DS */ b1->stmts = s; /* * If To DS is set, the DA is at 16. */ b0 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); gen_and(b1, b0); /* * Now, check for To DS not set, i.e. check * "!(link[1] & 0x01)". */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x01; /* To DS */ b2->stmts = s; gen_not(b2); /* * If To DS is not set, the DA is at 4. */ b1 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr); gen_and(b2, b1); /* * Now OR together the last two checks. That gives * the complete set of checks for data frames. */ gen_or(b1, b0); /* * Now check for a data frame. * I.e, check "link[0] & 0x08". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; /* * AND that with the checks done for data frames. */ gen_and(b1, b0); /* * If the high-order bit of the type value is 0, this * is a management frame. * I.e, check "!(link[0] & 0x08)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x08; b2->stmts = s; gen_not(b2); /* * For management frames, the DA is at 4. */ b1 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr); gen_and(b2, b1); /* * OR that with the checks done for data frames. * That gives the checks done for management and * data frames. */ gen_or(b1, b0); /* * If the low-order bit of the type value is 1, * this is either a control frame or a frame * with a reserved type, and thus not a * frame with an SA. * * I.e., check "!(link[0] & 0x04)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x04; b1->stmts = s; gen_not(b1); /* * AND that with the checks for data and management * frames. */ gen_and(b1, b0); return b0; case Q_RA: /* * Not present in management frames; addr1 in other * frames. */ /* * If the high-order bit of the type value is 0, this * is a management frame. * I.e, check "(link[0] & 0x08)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; /* * Check addr1. */ b0 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr); /* * AND that with the check of addr1. */ gen_and(b1, b0); return (b0); case Q_TA: /* * Not present in management frames; addr2, if present, * in other frames. */ /* * Not present in CTS or ACK control frames. */ b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_TYPE_MASK); gen_not(b0); b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, IEEE80211_FC0_SUBTYPE_MASK); gen_not(b1); b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, IEEE80211_FC0_SUBTYPE_MASK); gen_not(b2); gen_and(b1, b2); gen_or(b0, b2); /* * If the high-order bit of the type value is 0, this * is a management frame. * I.e, check "(link[0] & 0x08)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; /* * AND that with the check for frames other than * CTS and ACK frames. */ gen_and(b1, b2); /* * Check addr2. */ b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); return b1; /* * XXX - add BSSID keyword? */ case Q_ADDR1: return (gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr)); case Q_ADDR2: /* * Not present in CTS or ACK control frames. */ b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_TYPE_MASK); gen_not(b0); b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, IEEE80211_FC0_SUBTYPE_MASK); gen_not(b1); b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, IEEE80211_FC0_SUBTYPE_MASK); gen_not(b2); gen_and(b1, b2); gen_or(b0, b2); b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); return b1; case Q_ADDR3: /* * Not present in control frames. */ b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_TYPE_MASK); gen_not(b0); b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); gen_and(b0, b1); return b1; case Q_ADDR4: /* * Present only if the direction mask has both "From DS" * and "To DS" set. Neither control frames nor management * frames should have both of those set, so we don't * check the frame type. */ b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK); b1 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr); gen_and(b0, b1); return b1; case Q_AND: b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); b1 = gen_wlanhostop(cstate, eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); b1 = gen_wlanhostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; } abort(); /* NOTREACHED */ } /* * Like gen_ehostop, but for RFC 2625 IP-over-Fibre-Channel. * (We assume that the addresses are IEEE 48-bit MAC addresses, * as the RFC states.) */ static struct block * gen_ipfchostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { register struct block *b0, *b1; switch (dir) { case Q_SRC: return gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); case Q_DST: return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr); case Q_AND: b0 = gen_ipfchostop(cstate, eaddr, Q_SRC); b1 = gen_ipfchostop(cstate, eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_ipfchostop(cstate, eaddr, Q_SRC); b1 = gen_ipfchostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' is only supported on 802.11"); break; case Q_ADDR2: bpf_error(cstate, "'addr2' is only supported on 802.11"); break; case Q_ADDR3: bpf_error(cstate, "'addr3' is only supported on 802.11"); break; case Q_ADDR4: bpf_error(cstate, "'addr4' is only supported on 802.11"); break; case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11"); break; case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11"); break; } abort(); /* NOTREACHED */ } /* * This is quite tricky because there may be pad bytes in front of the * DECNET header, and then there are two possible data packet formats that * carry both src and dst addresses, plus 5 packet types in a format that * carries only the src node, plus 2 types that use a different format and * also carry just the src node. * * Yuck. * * Instead of doing those all right, we just look for data packets with * 0 or 1 bytes of padding. If you want to look at other packets, that * will require a lot more hacking. * * To add support for filtering on DECNET "areas" (network numbers) * one would want to add a "mask" argument to this routine. That would * make the filter even more inefficient, although one could be clever * and not generate masking instructions if the mask is 0xFFFF. */ static struct block * gen_dnhostop(compiler_state_t *cstate, bpf_u_int32 addr, int dir) { struct block *b0, *b1, *b2, *tmp; u_int offset_lh; /* offset if long header is received */ u_int offset_sh; /* offset if short header is received */ switch (dir) { case Q_DST: offset_sh = 1; /* follows flags */ offset_lh = 7; /* flgs,darea,dsubarea,HIORD */ break; case Q_SRC: offset_sh = 3; /* follows flags, dstnode */ offset_lh = 15; /* flgs,darea,dsubarea,did,sarea,ssub,HIORD */ break; case Q_AND: /* Inefficient because we do our Calvinball dance twice */ b0 = gen_dnhostop(cstate, addr, Q_SRC); b1 = gen_dnhostop(cstate, addr, Q_DST); gen_and(b0, b1); return b1; case Q_OR: case Q_DEFAULT: /* Inefficient because we do our Calvinball dance twice */ b0 = gen_dnhostop(cstate, addr, Q_SRC); b1 = gen_dnhostop(cstate, addr, Q_DST); gen_or(b0, b1); return b1; case Q_ISO: bpf_error(cstate, "ISO host filtering not implemented"); default: abort(); } b0 = gen_linktype(cstate, ETHERTYPE_DN); /* Check for pad = 1, long header case */ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H, (bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF)); b1 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr)); gen_and(tmp, b1); /* Check for pad = 0, long header case */ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7); b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr)); gen_and(tmp, b2); gen_or(b2, b1); /* Check for pad = 1, short header case */ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H, (bpf_int32)ntohs(0x0281), (bpf_int32)ntohs(0x07FF)); b2 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr)); gen_and(tmp, b2); gen_or(b2, b1); /* Check for pad = 0, short header case */ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_int32)0x02, (bpf_int32)0x7); b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr)); gen_and(tmp, b2); gen_or(b2, b1); /* Combine with test for cstate->linktype */ gen_and(b0, b1); return b1; } /* * Generate a check for IPv4 or IPv6 for MPLS-encapsulated packets; * test the bottom-of-stack bit, and then check the version number * field in the IP header. */ static struct block * gen_mpls_linktype(compiler_state_t *cstate, int proto) { struct block *b0, *b1; switch (proto) { case Q_IP: /* match the bottom-of-stack bit */ b0 = gen_mcmp(cstate, OR_LINKPL, -2, BPF_B, 0x01, 0x01); /* match the IPv4 version number */ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x40, 0xf0); gen_and(b0, b1); return b1; case Q_IPV6: /* match the bottom-of-stack bit */ b0 = gen_mcmp(cstate, OR_LINKPL, -2, BPF_B, 0x01, 0x01); /* match the IPv4 version number */ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x60, 0xf0); gen_and(b0, b1); return b1; default: abort(); } } static struct block * gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, int proto, int dir, int type) { struct block *b0, *b1; const char *typestr; if (type == Q_NET) typestr = "net"; else typestr = "host"; switch (proto) { case Q_DEFAULT: b0 = gen_host(cstate, addr, mask, Q_IP, dir, type); /* * Only check for non-IPv4 addresses if we're not * checking MPLS-encapsulated packets. */ if (cstate->label_stack_depth == 0) { b1 = gen_host(cstate, addr, mask, Q_ARP, dir, type); gen_or(b0, b1); b0 = gen_host(cstate, addr, mask, Q_RARP, dir, type); gen_or(b1, b0); } return b0; case Q_IP: return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_IP, 12, 16); case Q_RARP: return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_REVARP, 14, 24); case Q_ARP: return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_ARP, 14, 24); case Q_TCP: bpf_error(cstate, "'tcp' modifier applied to %s", typestr); case Q_SCTP: bpf_error(cstate, "'sctp' modifier applied to %s", typestr); case Q_UDP: bpf_error(cstate, "'udp' modifier applied to %s", typestr); case Q_ICMP: bpf_error(cstate, "'icmp' modifier applied to %s", typestr); case Q_IGMP: bpf_error(cstate, "'igmp' modifier applied to %s", typestr); case Q_IGRP: bpf_error(cstate, "'igrp' modifier applied to %s", typestr); case Q_PIM: bpf_error(cstate, "'pim' modifier applied to %s", typestr); case Q_VRRP: bpf_error(cstate, "'vrrp' modifier applied to %s", typestr); case Q_CARP: bpf_error(cstate, "'carp' modifier applied to %s", typestr); case Q_ATALK: bpf_error(cstate, "ATALK host filtering not implemented"); case Q_AARP: bpf_error(cstate, "AARP host filtering not implemented"); case Q_DECNET: return gen_dnhostop(cstate, addr, dir); case Q_SCA: bpf_error(cstate, "SCA host filtering not implemented"); case Q_LAT: bpf_error(cstate, "LAT host filtering not implemented"); case Q_MOPDL: bpf_error(cstate, "MOPDL host filtering not implemented"); case Q_MOPRC: bpf_error(cstate, "MOPRC host filtering not implemented"); case Q_IPV6: bpf_error(cstate, "'ip6' modifier applied to ip host"); case Q_ICMPV6: bpf_error(cstate, "'icmp6' modifier applied to %s", typestr); case Q_AH: bpf_error(cstate, "'ah' modifier applied to %s", typestr); case Q_ESP: bpf_error(cstate, "'esp' modifier applied to %s", typestr); case Q_ISO: bpf_error(cstate, "ISO host filtering not implemented"); case Q_ESIS: bpf_error(cstate, "'esis' modifier applied to %s", typestr); case Q_ISIS: bpf_error(cstate, "'isis' modifier applied to %s", typestr); case Q_CLNP: bpf_error(cstate, "'clnp' modifier applied to %s", typestr); case Q_STP: bpf_error(cstate, "'stp' modifier applied to %s", typestr); case Q_IPX: bpf_error(cstate, "IPX host filtering not implemented"); case Q_NETBEUI: bpf_error(cstate, "'netbeui' modifier applied to %s", typestr); case Q_RADIO: bpf_error(cstate, "'radio' modifier applied to %s", typestr); default: abort(); } /* NOTREACHED */ } #ifdef INET6 static struct block * gen_host6(compiler_state_t *cstate, struct in6_addr *addr, struct in6_addr *mask, int proto, int dir, int type) { const char *typestr; if (type == Q_NET) typestr = "net"; else typestr = "host"; switch (proto) { case Q_DEFAULT: return gen_host6(cstate, addr, mask, Q_IPV6, dir, type); case Q_LINK: bpf_error(cstate, "link-layer modifier applied to ip6 %s", typestr); case Q_IP: bpf_error(cstate, "'ip' modifier applied to ip6 %s", typestr); case Q_RARP: bpf_error(cstate, "'rarp' modifier applied to ip6 %s", typestr); case Q_ARP: bpf_error(cstate, "'arp' modifier applied to ip6 %s", typestr); case Q_SCTP: bpf_error(cstate, "'sctp' modifier applied to %s", typestr); case Q_TCP: bpf_error(cstate, "'tcp' modifier applied to %s", typestr); case Q_UDP: bpf_error(cstate, "'udp' modifier applied to %s", typestr); case Q_ICMP: bpf_error(cstate, "'icmp' modifier applied to %s", typestr); case Q_IGMP: bpf_error(cstate, "'igmp' modifier applied to %s", typestr); case Q_IGRP: bpf_error(cstate, "'igrp' modifier applied to %s", typestr); case Q_PIM: bpf_error(cstate, "'pim' modifier applied to %s", typestr); case Q_VRRP: bpf_error(cstate, "'vrrp' modifier applied to %s", typestr); case Q_CARP: bpf_error(cstate, "'carp' modifier applied to %s", typestr); case Q_ATALK: bpf_error(cstate, "ATALK host filtering not implemented"); case Q_AARP: bpf_error(cstate, "AARP host filtering not implemented"); case Q_DECNET: bpf_error(cstate, "'decnet' modifier applied to ip6 %s", typestr); case Q_SCA: bpf_error(cstate, "SCA host filtering not implemented"); case Q_LAT: bpf_error(cstate, "LAT host filtering not implemented"); case Q_MOPDL: bpf_error(cstate, "MOPDL host filtering not implemented"); case Q_MOPRC: bpf_error(cstate, "MOPRC host filtering not implemented"); case Q_IPV6: return gen_hostop6(cstate, addr, mask, dir, ETHERTYPE_IPV6, 8, 24); case Q_ICMPV6: bpf_error(cstate, "'icmp6' modifier applied to %s", typestr); case Q_AH: bpf_error(cstate, "'ah' modifier applied to %s", typestr); case Q_ESP: bpf_error(cstate, "'esp' modifier applied to %s", typestr); case Q_ISO: bpf_error(cstate, "ISO host filtering not implemented"); case Q_ESIS: bpf_error(cstate, "'esis' modifier applied to %s", typestr); case Q_ISIS: bpf_error(cstate, "'isis' modifier applied to %s", typestr); case Q_CLNP: bpf_error(cstate, "'clnp' modifier applied to %s", typestr); case Q_STP: bpf_error(cstate, "'stp' modifier applied to %s", typestr); case Q_IPX: bpf_error(cstate, "IPX host filtering not implemented"); case Q_NETBEUI: bpf_error(cstate, "'netbeui' modifier applied to %s", typestr); case Q_RADIO: bpf_error(cstate, "'radio' modifier applied to %s", typestr); default: abort(); } /* NOTREACHED */ } #endif #ifndef INET6 static struct block * gen_gateway(eaddr, alist, proto, dir) const u_char *eaddr; bpf_u_int32 **alist; int proto; int dir; { struct block *b0, *b1, *tmp; if (dir != 0) bpf_error(cstate, "direction applied to 'gateway'"); switch (proto) { case Q_DEFAULT: case Q_IP: case Q_ARP: case Q_RARP: switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: b1 = gen_prevlinkhdr_check(cstate); b0 = gen_ehostop(cstate, eaddr, Q_OR); if (b1 != NULL) gen_and(b1, b0); break; case DLT_FDDI: b0 = gen_fhostop(cstate, eaddr, Q_OR); break; case DLT_IEEE802: b0 = gen_thostop(cstate, eaddr, Q_OR); break; case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: b0 = gen_wlanhostop(cstate, eaddr, Q_OR); break; case DLT_SUNATM: /* * This is LLC-multiplexed traffic; if it were * LANE, cstate->linktype would have been set to * DLT_EN10MB. */ bpf_error(cstate, "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); break; case DLT_IP_OVER_FC: b0 = gen_ipfchostop(cstate, eaddr, Q_OR); break; default: bpf_error(cstate, "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); } b1 = gen_host(cstate, **alist++, 0xffffffff, proto, Q_OR, Q_HOST); while (*alist) { tmp = gen_host(cstate, **alist++, 0xffffffff, proto, Q_OR, Q_HOST); gen_or(b1, tmp); b1 = tmp; } gen_not(b1); gen_and(b0, b1); return b1; } bpf_error(cstate, "illegal modifier of 'gateway'"); /* NOTREACHED */ } #endif struct block * gen_proto_abbrev(compiler_state_t *cstate, int proto) { struct block *b0; struct block *b1; switch (proto) { case Q_SCTP: b1 = gen_proto(cstate, IPPROTO_SCTP, Q_IP, Q_DEFAULT); b0 = gen_proto(cstate, IPPROTO_SCTP, Q_IPV6, Q_DEFAULT); gen_or(b0, b1); break; case Q_TCP: b1 = gen_proto(cstate, IPPROTO_TCP, Q_IP, Q_DEFAULT); b0 = gen_proto(cstate, IPPROTO_TCP, Q_IPV6, Q_DEFAULT); gen_or(b0, b1); break; case Q_UDP: b1 = gen_proto(cstate, IPPROTO_UDP, Q_IP, Q_DEFAULT); b0 = gen_proto(cstate, IPPROTO_UDP, Q_IPV6, Q_DEFAULT); gen_or(b0, b1); break; case Q_ICMP: b1 = gen_proto(cstate, IPPROTO_ICMP, Q_IP, Q_DEFAULT); break; #ifndef IPPROTO_IGMP #define IPPROTO_IGMP 2 #endif case Q_IGMP: b1 = gen_proto(cstate, IPPROTO_IGMP, Q_IP, Q_DEFAULT); break; #ifndef IPPROTO_IGRP #define IPPROTO_IGRP 9 #endif case Q_IGRP: b1 = gen_proto(cstate, IPPROTO_IGRP, Q_IP, Q_DEFAULT); break; #ifndef IPPROTO_PIM #define IPPROTO_PIM 103 #endif case Q_PIM: b1 = gen_proto(cstate, IPPROTO_PIM, Q_IP, Q_DEFAULT); b0 = gen_proto(cstate, IPPROTO_PIM, Q_IPV6, Q_DEFAULT); gen_or(b0, b1); break; #ifndef IPPROTO_VRRP #define IPPROTO_VRRP 112 #endif case Q_VRRP: b1 = gen_proto(cstate, IPPROTO_VRRP, Q_IP, Q_DEFAULT); break; #ifndef IPPROTO_CARP #define IPPROTO_CARP 112 #endif case Q_CARP: b1 = gen_proto(cstate, IPPROTO_CARP, Q_IP, Q_DEFAULT); break; case Q_IP: b1 = gen_linktype(cstate, ETHERTYPE_IP); break; case Q_ARP: b1 = gen_linktype(cstate, ETHERTYPE_ARP); break; case Q_RARP: b1 = gen_linktype(cstate, ETHERTYPE_REVARP); break; case Q_LINK: bpf_error(cstate, "link layer applied in wrong context"); case Q_ATALK: b1 = gen_linktype(cstate, ETHERTYPE_ATALK); break; case Q_AARP: b1 = gen_linktype(cstate, ETHERTYPE_AARP); break; case Q_DECNET: b1 = gen_linktype(cstate, ETHERTYPE_DN); break; case Q_SCA: b1 = gen_linktype(cstate, ETHERTYPE_SCA); break; case Q_LAT: b1 = gen_linktype(cstate, ETHERTYPE_LAT); break; case Q_MOPDL: b1 = gen_linktype(cstate, ETHERTYPE_MOPDL); break; case Q_MOPRC: b1 = gen_linktype(cstate, ETHERTYPE_MOPRC); break; case Q_IPV6: b1 = gen_linktype(cstate, ETHERTYPE_IPV6); break; #ifndef IPPROTO_ICMPV6 #define IPPROTO_ICMPV6 58 #endif case Q_ICMPV6: b1 = gen_proto(cstate, IPPROTO_ICMPV6, Q_IPV6, Q_DEFAULT); break; #ifndef IPPROTO_AH #define IPPROTO_AH 51 #endif case Q_AH: b1 = gen_proto(cstate, IPPROTO_AH, Q_IP, Q_DEFAULT); b0 = gen_proto(cstate, IPPROTO_AH, Q_IPV6, Q_DEFAULT); gen_or(b0, b1); break; #ifndef IPPROTO_ESP #define IPPROTO_ESP 50 #endif case Q_ESP: b1 = gen_proto(cstate, IPPROTO_ESP, Q_IP, Q_DEFAULT); b0 = gen_proto(cstate, IPPROTO_ESP, Q_IPV6, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISO: b1 = gen_linktype(cstate, LLCSAP_ISONS); break; case Q_ESIS: b1 = gen_proto(cstate, ISO9542_ESIS, Q_ISO, Q_DEFAULT); break; case Q_ISIS: b1 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT); break; case Q_ISIS_L1: /* all IS-IS Level1 PDU-Types */ b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */ gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_L2: /* all IS-IS Level2 PDU-Types */ b0 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */ gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_IIH: /* all IS-IS Hello PDU-Types */ b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_LSP: b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_SNP: b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_CSNP: b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_PSNP: b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_CLNP: b1 = gen_proto(cstate, ISO8473_CLNP, Q_ISO, Q_DEFAULT); break; case Q_STP: b1 = gen_linktype(cstate, LLCSAP_8021D); break; case Q_IPX: b1 = gen_linktype(cstate, LLCSAP_IPX); break; case Q_NETBEUI: b1 = gen_linktype(cstate, LLCSAP_NETBEUI); break; case Q_RADIO: bpf_error(cstate, "'radio' is not a valid protocol type"); default: abort(); } return b1; } static struct block * gen_ipfrag(compiler_state_t *cstate) { struct slist *s; struct block *b; /* not IPv4 frag other than the first frag */ s = gen_load_a(cstate, OR_LINKPL, 6, BPF_H); b = new_block(cstate, JMP(BPF_JSET)); b->s.k = 0x1fff; b->stmts = s; gen_not(b); return b; } /* * Generate a comparison to a port value in the transport-layer header * at the specified offset from the beginning of that header. * * XXX - this handles a variable-length prefix preceding the link-layer * header, such as the radiotap or AVS radio prefix, but doesn't handle * variable-length link-layer headers (such as Token Ring or 802.11 * headers). */ static struct block * gen_portatom(compiler_state_t *cstate, int off, bpf_int32 v) { return gen_cmp(cstate, OR_TRAN_IPV4, off, BPF_H, v); } static struct block * gen_portatom6(compiler_state_t *cstate, int off, bpf_int32 v) { return gen_cmp(cstate, OR_TRAN_IPV6, off, BPF_H, v); } struct block * gen_portop(compiler_state_t *cstate, int port, int proto, int dir) { struct block *b0, *b1, *tmp; /* ip proto 'proto' and not a fragment other than the first fragment */ tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, (bpf_int32)proto); b0 = gen_ipfrag(cstate); gen_and(tmp, b0); switch (dir) { case Q_SRC: b1 = gen_portatom(cstate, 0, (bpf_int32)port); break; case Q_DST: b1 = gen_portatom(cstate, 2, (bpf_int32)port); break; case Q_OR: case Q_DEFAULT: tmp = gen_portatom(cstate, 0, (bpf_int32)port); b1 = gen_portatom(cstate, 2, (bpf_int32)port); gen_or(tmp, b1); break; case Q_AND: tmp = gen_portatom(cstate, 0, (bpf_int32)port); b1 = gen_portatom(cstate, 2, (bpf_int32)port); gen_and(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } static struct block * gen_port(compiler_state_t *cstate, int port, int ip_proto, int dir) { struct block *b0, *b1, *tmp; /* * ether proto ip * * For FDDI, RFC 1188 says that SNAP encapsulation is used, * not LLC encapsulation with LLCSAP_IP. * * For IEEE 802 networks - which includes 802.5 token ring * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042 * says that SNAP encapsulation is used, not LLC encapsulation * with LLCSAP_IP. * * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and * RFC 2225 say that SNAP encapsulation is used, not LLC * encapsulation with LLCSAP_IP. * * So we always check for ETHERTYPE_IP. */ b0 = gen_linktype(cstate, ETHERTYPE_IP); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: b1 = gen_portop(cstate, port, ip_proto, dir); break; case PROTO_UNDEF: tmp = gen_portop(cstate, port, IPPROTO_TCP, dir); b1 = gen_portop(cstate, port, IPPROTO_UDP, dir); gen_or(tmp, b1); tmp = gen_portop(cstate, port, IPPROTO_SCTP, dir); gen_or(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } struct block * gen_portop6(compiler_state_t *cstate, int port, int proto, int dir) { struct block *b0, *b1, *tmp; /* ip6 proto 'proto' */ /* XXX - catch the first fragment of a fragmented packet? */ b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)proto); switch (dir) { case Q_SRC: b1 = gen_portatom6(cstate, 0, (bpf_int32)port); break; case Q_DST: b1 = gen_portatom6(cstate, 2, (bpf_int32)port); break; case Q_OR: case Q_DEFAULT: tmp = gen_portatom6(cstate, 0, (bpf_int32)port); b1 = gen_portatom6(cstate, 2, (bpf_int32)port); gen_or(tmp, b1); break; case Q_AND: tmp = gen_portatom6(cstate, 0, (bpf_int32)port); b1 = gen_portatom6(cstate, 2, (bpf_int32)port); gen_and(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } static struct block * gen_port6(compiler_state_t *cstate, int port, int ip_proto, int dir) { struct block *b0, *b1, *tmp; /* link proto ip6 */ b0 = gen_linktype(cstate, ETHERTYPE_IPV6); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: b1 = gen_portop6(cstate, port, ip_proto, dir); break; case PROTO_UNDEF: tmp = gen_portop6(cstate, port, IPPROTO_TCP, dir); b1 = gen_portop6(cstate, port, IPPROTO_UDP, dir); gen_or(tmp, b1); tmp = gen_portop6(cstate, port, IPPROTO_SCTP, dir); gen_or(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } /* gen_portrange code */ static struct block * gen_portrangeatom(compiler_state_t *cstate, int off, bpf_int32 v1, bpf_int32 v2) { struct block *b1, *b2; if (v1 > v2) { /* * Reverse the order of the ports, so v1 is the lower one. */ bpf_int32 vtemp; vtemp = v1; v1 = v2; v2 = vtemp; } b1 = gen_cmp_ge(cstate, OR_TRAN_IPV4, off, BPF_H, v1); b2 = gen_cmp_le(cstate, OR_TRAN_IPV4, off, BPF_H, v2); gen_and(b1, b2); return b2; } struct block * gen_portrangeop(compiler_state_t *cstate, int port1, int port2, int proto, int dir) { struct block *b0, *b1, *tmp; /* ip proto 'proto' and not a fragment other than the first fragment */ tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, (bpf_int32)proto); b0 = gen_ipfrag(cstate); gen_and(tmp, b0); switch (dir) { case Q_SRC: b1 = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); break; case Q_DST: b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); break; case Q_OR: case Q_DEFAULT: tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); gen_or(tmp, b1); break; case Q_AND: tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); gen_and(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } static struct block * gen_portrange(compiler_state_t *cstate, int port1, int port2, int ip_proto, int dir) { struct block *b0, *b1, *tmp; /* link proto ip */ b0 = gen_linktype(cstate, ETHERTYPE_IP); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: b1 = gen_portrangeop(cstate, port1, port2, ip_proto, dir); break; case PROTO_UNDEF: tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_TCP, dir); b1 = gen_portrangeop(cstate, port1, port2, IPPROTO_UDP, dir); gen_or(tmp, b1); tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_SCTP, dir); gen_or(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } static struct block * gen_portrangeatom6(compiler_state_t *cstate, int off, bpf_int32 v1, bpf_int32 v2) { struct block *b1, *b2; if (v1 > v2) { /* * Reverse the order of the ports, so v1 is the lower one. */ bpf_int32 vtemp; vtemp = v1; v1 = v2; v2 = vtemp; } b1 = gen_cmp_ge(cstate, OR_TRAN_IPV6, off, BPF_H, v1); b2 = gen_cmp_le(cstate, OR_TRAN_IPV6, off, BPF_H, v2); gen_and(b1, b2); return b2; } struct block * gen_portrangeop6(compiler_state_t *cstate, int port1, int port2, int proto, int dir) { struct block *b0, *b1, *tmp; /* ip6 proto 'proto' */ /* XXX - catch the first fragment of a fragmented packet? */ b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)proto); switch (dir) { case Q_SRC: b1 = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); break; case Q_DST: b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); break; case Q_OR: case Q_DEFAULT: tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); gen_or(tmp, b1); break; case Q_AND: tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); gen_and(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } static struct block * gen_portrange6(compiler_state_t *cstate, int port1, int port2, int ip_proto, int dir) { struct block *b0, *b1, *tmp; /* link proto ip6 */ b0 = gen_linktype(cstate, ETHERTYPE_IPV6); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: b1 = gen_portrangeop6(cstate, port1, port2, ip_proto, dir); break; case PROTO_UNDEF: tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_TCP, dir); b1 = gen_portrangeop6(cstate, port1, port2, IPPROTO_UDP, dir); gen_or(tmp, b1); tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_SCTP, dir); gen_or(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } static int lookup_proto(compiler_state_t *cstate, const char *name, int proto) { register int v; switch (proto) { case Q_DEFAULT: case Q_IP: case Q_IPV6: v = pcap_nametoproto(name); if (v == PROTO_UNDEF) bpf_error(cstate, "unknown ip proto '%s'", name); break; case Q_LINK: /* XXX should look up h/w protocol type based on cstate->linktype */ v = pcap_nametoeproto(name); if (v == PROTO_UNDEF) { v = pcap_nametollc(name); if (v == PROTO_UNDEF) bpf_error(cstate, "unknown ether proto '%s'", name); } break; case Q_ISO: if (strcmp(name, "esis") == 0) v = ISO9542_ESIS; else if (strcmp(name, "isis") == 0) v = ISO10589_ISIS; else if (strcmp(name, "clnp") == 0) v = ISO8473_CLNP; else bpf_error(cstate, "unknown osi proto '%s'", name); break; default: v = PROTO_UNDEF; break; } return v; } #if 0 struct stmt * gen_joinsp(s, n) struct stmt **s; int n; { return NULL; } #endif static struct block * gen_protochain(compiler_state_t *cstate, int v, int proto, int dir) { #ifdef NO_PROTOCHAIN return gen_proto(cstate, v, proto, dir); #else struct block *b0, *b; struct slist *s[100]; int fix2, fix3, fix4, fix5; int ahcheck, again, end; int i, max; int reg2 = alloc_reg(cstate); memset(s, 0, sizeof(s)); fix3 = fix4 = fix5 = 0; switch (proto) { case Q_IP: case Q_IPV6: break; case Q_DEFAULT: b0 = gen_protochain(cstate, v, Q_IP, dir); b = gen_protochain(cstate, v, Q_IPV6, dir); gen_or(b0, b); return b; default: bpf_error(cstate, "bad protocol applied for 'protochain'"); /*NOTREACHED*/ } /* * We don't handle variable-length prefixes before the link-layer * header, or variable-length link-layer headers, here yet. * We might want to add BPF instructions to do the protochain * work, to simplify that and, on platforms that have a BPF * interpreter with the new instructions, let the filtering * be done in the kernel. (We already require a modified BPF * engine to do the protochain stuff, to support backward * branches, and backward branch support is unlikely to appear * in kernel BPF engines.) */ if (cstate->off_linkpl.is_variable) bpf_error(cstate, "'protochain' not supported with variable length headers"); cstate->no_optimize = 1; /*this code is not compatible with optimzer yet */ /* * s[0] is a dummy entry to protect other BPF insn from damage * by s[fix] = foo with uninitialized variable "fix". It is somewhat * hard to find interdependency made by jump table fixup. */ i = 0; s[i] = new_stmt(cstate, 0); /*dummy*/ i++; switch (proto) { case Q_IP: b0 = gen_linktype(cstate, ETHERTYPE_IP); /* A = ip->ip_p */ s[i] = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 9; i++; /* X = ip->ip_hl << 2 */ s[i] = new_stmt(cstate, BPF_LDX|BPF_MSH|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; i++; break; case Q_IPV6: b0 = gen_linktype(cstate, ETHERTYPE_IPV6); /* A = ip6->ip_nxt */ s[i] = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 6; i++; /* X = sizeof(struct ip6_hdr) */ s[i] = new_stmt(cstate, BPF_LDX|BPF_IMM); s[i]->s.k = 40; i++; break; default: bpf_error(cstate, "unsupported proto to gen_protochain"); /*NOTREACHED*/ } /* again: if (A == v) goto end; else fall through; */ again = i; s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.k = v; s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*update in next stmt*/ fix5 = i; i++; #ifndef IPPROTO_NONE #define IPPROTO_NONE 59 #endif /* if (A == IPPROTO_NONE) goto end */ s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*update in next stmt*/ s[i]->s.k = IPPROTO_NONE; s[fix5]->s.jf = s[i]; fix2 = i; i++; if (proto == Q_IPV6) { int v6start, v6end, v6advance, j; v6start = i; /* if (A == IPPROTO_HOPOPTS) goto v6advance */ s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*update in next stmt*/ s[i]->s.k = IPPROTO_HOPOPTS; s[fix2]->s.jf = s[i]; i++; /* if (A == IPPROTO_DSTOPTS) goto v6advance */ s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*update in next stmt*/ s[i]->s.k = IPPROTO_DSTOPTS; i++; /* if (A == IPPROTO_ROUTING) goto v6advance */ s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*update in next stmt*/ s[i]->s.k = IPPROTO_ROUTING; i++; /* if (A == IPPROTO_FRAGMENT) goto v6advance; else goto ahcheck; */ s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*later*/ s[i]->s.k = IPPROTO_FRAGMENT; fix3 = i; v6end = i; i++; /* v6advance: */ v6advance = i; /* * in short, * A = P[X + packet head]; * X = X + (P[X + packet head + 1] + 1) * 8; */ /* A = P[X + packet head] */ s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; i++; /* MEM[reg2] = A */ s[i] = new_stmt(cstate, BPF_ST); s[i]->s.k = reg2; i++; /* A = P[X + packet head + 1]; */ s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 1; i++; /* A += 1 */ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 1; i++; /* A *= 8 */ s[i] = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K); s[i]->s.k = 8; i++; /* A += X */ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X); s[i]->s.k = 0; i++; /* X = A; */ s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX); i++; /* A = MEM[reg2] */ s[i] = new_stmt(cstate, BPF_LD|BPF_MEM); s[i]->s.k = reg2; i++; /* goto again; (must use BPF_JA for backward jump) */ s[i] = new_stmt(cstate, BPF_JMP|BPF_JA); s[i]->s.k = again - i - 1; s[i - 1]->s.jf = s[i]; i++; /* fixup */ for (j = v6start; j <= v6end; j++) s[j]->s.jt = s[v6advance]; } else { /* nop */ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 0; s[fix2]->s.jf = s[i]; i++; } /* ahcheck: */ ahcheck = i; /* if (A == IPPROTO_AH) then fall through; else goto end; */ s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*later*/ s[i]->s.k = IPPROTO_AH; if (fix3) s[fix3]->s.jf = s[ahcheck]; fix4 = i; i++; /* * in short, * A = P[X]; * X = X + (P[X + 1] + 2) * 4; */ /* A = X */ s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA); i++; /* A = P[X + packet head]; */ s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; i++; /* MEM[reg2] = A */ s[i] = new_stmt(cstate, BPF_ST); s[i]->s.k = reg2; i++; /* A = X */ s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA); i++; /* A += 1 */ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 1; i++; /* X = A */ s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX); i++; /* A = P[X + packet head] */ s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; i++; /* A += 2 */ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 2; i++; /* A *= 4 */ s[i] = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K); s[i]->s.k = 4; i++; /* X = A; */ s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX); i++; /* A = MEM[reg2] */ s[i] = new_stmt(cstate, BPF_LD|BPF_MEM); s[i]->s.k = reg2; i++; /* goto again; (must use BPF_JA for backward jump) */ s[i] = new_stmt(cstate, BPF_JMP|BPF_JA); s[i]->s.k = again - i - 1; i++; /* end: nop */ end = i; s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 0; s[fix2]->s.jt = s[end]; s[fix4]->s.jf = s[end]; s[fix5]->s.jt = s[end]; i++; /* * make slist chain */ max = i; for (i = 0; i < max - 1; i++) s[i]->next = s[i + 1]; s[max - 1]->next = NULL; /* * emit final check */ b = new_block(cstate, JMP(BPF_JEQ)); b->stmts = s[1]; /*remember, s[0] is dummy*/ b->s.k = v; free_reg(cstate, reg2); gen_and(b0, b); return b; #endif } static struct block * gen_check_802_11_data_frame(compiler_state_t *cstate) { struct slist *s; struct block *b0, *b1; /* * A data frame has the 0x08 bit (b3) in the frame control field set * and the 0x04 bit (b2) clear. */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b0 = new_block(cstate, JMP(BPF_JSET)); b0->s.k = 0x08; b0->stmts = s; s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x04; b1->stmts = s; gen_not(b1); gen_and(b1, b0); return b0; } /* * Generate code that checks whether the packet is a packet for protocol * and whether the type field in that protocol's header has * the value , e.g. if is Q_IP, it checks whether it's an * IP packet and checks the protocol number in the IP header against . * * If is Q_DEFAULT, i.e. just "proto" was specified, it checks * against Q_IP and Q_IPV6. */ static struct block * gen_proto(compiler_state_t *cstate, int v, int proto, int dir) { struct block *b0, *b1; #ifndef CHASE_CHAIN struct block *b2; #endif if (dir != Q_DEFAULT) bpf_error(cstate, "direction applied to 'proto'"); switch (proto) { case Q_DEFAULT: b0 = gen_proto(cstate, v, Q_IP, dir); b1 = gen_proto(cstate, v, Q_IPV6, dir); gen_or(b0, b1); return b1; case Q_IP: /* * For FDDI, RFC 1188 says that SNAP encapsulation is used, * not LLC encapsulation with LLCSAP_IP. * * For IEEE 802 networks - which includes 802.5 token ring * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042 * says that SNAP encapsulation is used, not LLC encapsulation * with LLCSAP_IP. * * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and * RFC 2225 say that SNAP encapsulation is used, not LLC * encapsulation with LLCSAP_IP. * * So we always check for ETHERTYPE_IP. */ b0 = gen_linktype(cstate, ETHERTYPE_IP); #ifndef CHASE_CHAIN b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, (bpf_int32)v); #else b1 = gen_protochain(cstate, v, Q_IP); #endif gen_and(b0, b1); return b1; case Q_ISO: switch (cstate->linktype) { case DLT_FRELAY: /* * Frame Relay packets typically have an OSI * NLPID at the beginning; "gen_linktype(cstate, LLCSAP_ISONS)" * generates code to check for all the OSI * NLPIDs, so calling it and then adding a check * for the particular NLPID for which we're * looking is bogus, as we can just check for * the NLPID. * * What we check for is the NLPID and a frame * control field value of UI, i.e. 0x03 followed * by the NLPID. * * XXX - assumes a 2-byte Frame Relay header with * DLCI and flags. What if the address is longer? * * XXX - what about SNAP-encapsulated frames? */ return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | v); /*NOTREACHED*/ break; case DLT_C_HDLC: /* * Cisco uses an Ethertype lookalike - for OSI, * it's 0xfefe. */ b0 = gen_linktype(cstate, LLCSAP_ISONS<<8 | LLCSAP_ISONS); /* OSI in C-HDLC is stuffed with a fudge byte */ b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, (long)v); gen_and(b0, b1); return b1; default: b0 = gen_linktype(cstate, LLCSAP_ISONS); b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, (long)v); gen_and(b0, b1); return b1; } case Q_ISIS: b0 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT); /* * 4 is the offset of the PDU type relative to the IS-IS * header. */ b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, (long)v); gen_and(b0, b1); return b1; case Q_ARP: bpf_error(cstate, "arp does not encapsulate another protocol"); /* NOTREACHED */ case Q_RARP: bpf_error(cstate, "rarp does not encapsulate another protocol"); /* NOTREACHED */ case Q_ATALK: bpf_error(cstate, "atalk encapsulation is not specifiable"); /* NOTREACHED */ case Q_DECNET: bpf_error(cstate, "decnet encapsulation is not specifiable"); /* NOTREACHED */ case Q_SCA: bpf_error(cstate, "sca does not encapsulate another protocol"); /* NOTREACHED */ case Q_LAT: bpf_error(cstate, "lat does not encapsulate another protocol"); /* NOTREACHED */ case Q_MOPRC: bpf_error(cstate, "moprc does not encapsulate another protocol"); /* NOTREACHED */ case Q_MOPDL: bpf_error(cstate, "mopdl does not encapsulate another protocol"); /* NOTREACHED */ case Q_LINK: return gen_linktype(cstate, v); case Q_UDP: bpf_error(cstate, "'udp proto' is bogus"); /* NOTREACHED */ case Q_TCP: bpf_error(cstate, "'tcp proto' is bogus"); /* NOTREACHED */ case Q_SCTP: bpf_error(cstate, "'sctp proto' is bogus"); /* NOTREACHED */ case Q_ICMP: bpf_error(cstate, "'icmp proto' is bogus"); /* NOTREACHED */ case Q_IGMP: bpf_error(cstate, "'igmp proto' is bogus"); /* NOTREACHED */ case Q_IGRP: bpf_error(cstate, "'igrp proto' is bogus"); /* NOTREACHED */ case Q_PIM: bpf_error(cstate, "'pim proto' is bogus"); /* NOTREACHED */ case Q_VRRP: bpf_error(cstate, "'vrrp proto' is bogus"); /* NOTREACHED */ case Q_CARP: bpf_error(cstate, "'carp proto' is bogus"); /* NOTREACHED */ case Q_IPV6: b0 = gen_linktype(cstate, ETHERTYPE_IPV6); #ifndef CHASE_CHAIN /* * Also check for a fragment header before the final * header. */ b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT); b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, (bpf_int32)v); gen_and(b2, b1); b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)v); gen_or(b2, b1); #else b1 = gen_protochain(cstate, v, Q_IPV6); #endif gen_and(b0, b1); return b1; case Q_ICMPV6: bpf_error(cstate, "'icmp6 proto' is bogus"); case Q_AH: bpf_error(cstate, "'ah proto' is bogus"); case Q_ESP: bpf_error(cstate, "'ah proto' is bogus"); case Q_STP: bpf_error(cstate, "'stp proto' is bogus"); case Q_IPX: bpf_error(cstate, "'ipx proto' is bogus"); case Q_NETBEUI: bpf_error(cstate, "'netbeui proto' is bogus"); case Q_RADIO: bpf_error(cstate, "'radio proto' is bogus"); default: abort(); /* NOTREACHED */ } /* NOTREACHED */ } struct block * gen_scode(compiler_state_t *cstate, const char *name, struct qual q) { int proto = q.proto; int dir = q.dir; int tproto; u_char *eaddr; bpf_u_int32 mask, addr; #ifndef INET6 bpf_u_int32 **alist; #else int tproto6; struct sockaddr_in *sin4; struct sockaddr_in6 *sin6; struct addrinfo *res, *res0; struct in6_addr mask128; #endif /*INET6*/ struct block *b, *tmp; int port, real_proto; int port1, port2; switch (q.addr) { case Q_NET: addr = pcap_nametonetaddr(name); if (addr == 0) bpf_error(cstate, "unknown network '%s'", name); /* Left justify network addr and calculate its network mask */ mask = 0xffffffff; while (addr && (addr & 0xff000000) == 0) { addr <<= 8; mask <<= 8; } return gen_host(cstate, addr, mask, proto, dir, q.addr); case Q_DEFAULT: case Q_HOST: if (proto == Q_LINK) { switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error(cstate, "unknown ether host '%s'", name); tmp = gen_prevlinkhdr_check(cstate); b = gen_ehostop(cstate, eaddr, dir); if (tmp != NULL) gen_and(tmp, b); free(eaddr); return b; case DLT_FDDI: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error(cstate, "unknown FDDI host '%s'", name); b = gen_fhostop(cstate, eaddr, dir); free(eaddr); return b; case DLT_IEEE802: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error(cstate, "unknown token ring host '%s'", name); b = gen_thostop(cstate, eaddr, dir); free(eaddr); return b; case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error(cstate, "unknown 802.11 host '%s'", name); b = gen_wlanhostop(cstate, eaddr, dir); free(eaddr); return b; case DLT_IP_OVER_FC: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error(cstate, "unknown Fibre Channel host '%s'", name); b = gen_ipfchostop(cstate, eaddr, dir); free(eaddr); return b; } bpf_error(cstate, "only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name"); } else if (proto == Q_DECNET) { unsigned short dn_addr; if (!__pcap_nametodnaddr(name, &dn_addr)) { #ifdef DECNETLIB bpf_error(cstate, "unknown decnet host name '%s'\n", name); #else bpf_error(cstate, "decnet name support not included, '%s' cannot be translated\n", name); #endif } /* * I don't think DECNET hosts can be multihomed, so * there is no need to build up a list of addresses */ return (gen_host(cstate, dn_addr, 0, proto, dir, q.addr)); } else { #ifndef INET6 alist = pcap_nametoaddr(name); if (alist == NULL || *alist == NULL) bpf_error(cstate, "unknown host '%s'", name); tproto = proto; if (cstate->off_linktype.constant_part == OFFSET_NOT_SET && tproto == Q_DEFAULT) tproto = Q_IP; b = gen_host(cstate, **alist++, 0xffffffff, tproto, dir, q.addr); while (*alist) { tmp = gen_host(cstate, **alist++, 0xffffffff, tproto, dir, q.addr); gen_or(b, tmp); b = tmp; } return b; #else memset(&mask128, 0xff, sizeof(mask128)); res0 = res = pcap_nametoaddrinfo(name); if (res == NULL) bpf_error(cstate, "unknown host '%s'", name); cstate->ai = res; b = tmp = NULL; tproto = tproto6 = proto; if (cstate->off_linktype.constant_part == OFFSET_NOT_SET && tproto == Q_DEFAULT) { tproto = Q_IP; tproto6 = Q_IPV6; } for (res = res0; res; res = res->ai_next) { switch (res->ai_family) { case AF_INET: if (tproto == Q_IPV6) continue; sin4 = (struct sockaddr_in *) res->ai_addr; tmp = gen_host(cstate, ntohl(sin4->sin_addr.s_addr), 0xffffffff, tproto, dir, q.addr); break; case AF_INET6: if (tproto6 == Q_IP) continue; sin6 = (struct sockaddr_in6 *) res->ai_addr; tmp = gen_host6(cstate, &sin6->sin6_addr, &mask128, tproto6, dir, q.addr); break; default: continue; } if (b) gen_or(b, tmp); b = tmp; } cstate->ai = NULL; freeaddrinfo(res0); if (b == NULL) { bpf_error(cstate, "unknown host '%s'%s", name, (proto == Q_DEFAULT) ? "" : " for specified address family"); } return b; #endif /*INET6*/ } case Q_PORT: if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP) bpf_error(cstate, "illegal qualifier of 'port'"); if (pcap_nametoport(name, &port, &real_proto) == 0) bpf_error(cstate, "unknown port '%s'", name); if (proto == Q_UDP) { if (real_proto == IPPROTO_TCP) bpf_error(cstate, "port '%s' is tcp", name); else if (real_proto == IPPROTO_SCTP) bpf_error(cstate, "port '%s' is sctp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_UDP; } if (proto == Q_TCP) { if (real_proto == IPPROTO_UDP) bpf_error(cstate, "port '%s' is udp", name); else if (real_proto == IPPROTO_SCTP) bpf_error(cstate, "port '%s' is sctp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_TCP; } if (proto == Q_SCTP) { if (real_proto == IPPROTO_UDP) bpf_error(cstate, "port '%s' is udp", name); else if (real_proto == IPPROTO_TCP) bpf_error(cstate, "port '%s' is tcp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_SCTP; } if (port < 0) bpf_error(cstate, "illegal port number %d < 0", port); if (port > 65535) bpf_error(cstate, "illegal port number %d > 65535", port); b = gen_port(cstate, port, real_proto, dir); gen_or(gen_port6(cstate, port, real_proto, dir), b); return b; case Q_PORTRANGE: if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP) bpf_error(cstate, "illegal qualifier of 'portrange'"); if (pcap_nametoportrange(name, &port1, &port2, &real_proto) == 0) bpf_error(cstate, "unknown port in range '%s'", name); if (proto == Q_UDP) { if (real_proto == IPPROTO_TCP) bpf_error(cstate, "port in range '%s' is tcp", name); else if (real_proto == IPPROTO_SCTP) bpf_error(cstate, "port in range '%s' is sctp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_UDP; } if (proto == Q_TCP) { if (real_proto == IPPROTO_UDP) bpf_error(cstate, "port in range '%s' is udp", name); else if (real_proto == IPPROTO_SCTP) bpf_error(cstate, "port in range '%s' is sctp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_TCP; } if (proto == Q_SCTP) { if (real_proto == IPPROTO_UDP) bpf_error(cstate, "port in range '%s' is udp", name); else if (real_proto == IPPROTO_TCP) bpf_error(cstate, "port in range '%s' is tcp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_SCTP; } if (port1 < 0) bpf_error(cstate, "illegal port number %d < 0", port1); if (port1 > 65535) bpf_error(cstate, "illegal port number %d > 65535", port1); if (port2 < 0) bpf_error(cstate, "illegal port number %d < 0", port2); if (port2 > 65535) bpf_error(cstate, "illegal port number %d > 65535", port2); b = gen_portrange(cstate, port1, port2, real_proto, dir); gen_or(gen_portrange6(cstate, port1, port2, real_proto, dir), b); return b; case Q_GATEWAY: #ifndef INET6 eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error(cstate, "unknown ether host: %s", name); alist = pcap_nametoaddr(name); if (alist == NULL || *alist == NULL) bpf_error(cstate, "unknown host '%s'", name); b = gen_gateway(eaddr, alist, proto, dir); free(eaddr); return b; #else bpf_error(cstate, "'gateway' not supported in this configuration"); #endif /*INET6*/ case Q_PROTO: real_proto = lookup_proto(cstate, name, proto); if (real_proto >= 0) return gen_proto(cstate, real_proto, proto, dir); else bpf_error(cstate, "unknown protocol: %s", name); case Q_PROTOCHAIN: real_proto = lookup_proto(cstate, name, proto); if (real_proto >= 0) return gen_protochain(cstate, real_proto, proto, dir); else bpf_error(cstate, "unknown protocol: %s", name); case Q_UNDEF: syntax(cstate); /* NOTREACHED */ } abort(); /* NOTREACHED */ } struct block * gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2, unsigned int masklen, struct qual q) { register int nlen, mlen; bpf_u_int32 n, m; nlen = __pcap_atoin(s1, &n); /* Promote short ipaddr */ n <<= 32 - nlen; if (s2 != NULL) { mlen = __pcap_atoin(s2, &m); /* Promote short ipaddr */ m <<= 32 - mlen; if ((n & ~m) != 0) bpf_error(cstate, "non-network bits set in \"%s mask %s\"", s1, s2); } else { /* Convert mask len to mask */ if (masklen > 32) bpf_error(cstate, "mask length must be <= 32"); if (masklen == 0) { /* * X << 32 is not guaranteed by C to be 0; it's * undefined. */ m = 0; } else m = 0xffffffff << (32 - masklen); if ((n & ~m) != 0) bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen); } switch (q.addr) { case Q_NET: return gen_host(cstate, n, m, q.proto, q.dir, q.addr); default: bpf_error(cstate, "Mask syntax for networks only"); /* NOTREACHED */ } /* NOTREACHED */ return NULL; } struct block * gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q) { bpf_u_int32 mask; int proto = q.proto; int dir = q.dir; register int vlen; if (s == NULL) vlen = 32; else if (q.proto == Q_DECNET) { vlen = __pcap_atodn(s, &v); if (vlen == 0) bpf_error(cstate, "malformed decnet address '%s'", s); } else vlen = __pcap_atoin(s, &v); switch (q.addr) { case Q_DEFAULT: case Q_HOST: case Q_NET: if (proto == Q_DECNET) return gen_host(cstate, v, 0, proto, dir, q.addr); else if (proto == Q_LINK) { bpf_error(cstate, "illegal link layer address"); } else { mask = 0xffffffff; if (s == NULL && q.addr == Q_NET) { /* Promote short net number */ while (v && (v & 0xff000000) == 0) { v <<= 8; mask <<= 8; } } else { /* Promote short ipaddr */ v <<= 32 - vlen; mask <<= 32 - vlen ; } return gen_host(cstate, v, mask, proto, dir, q.addr); } case Q_PORT: if (proto == Q_UDP) proto = IPPROTO_UDP; else if (proto == Q_TCP) proto = IPPROTO_TCP; else if (proto == Q_SCTP) proto = IPPROTO_SCTP; else if (proto == Q_DEFAULT) proto = PROTO_UNDEF; else bpf_error(cstate, "illegal qualifier of 'port'"); if (v > 65535) bpf_error(cstate, "illegal port number %u > 65535", v); { struct block *b; b = gen_port(cstate, (int)v, proto, dir); gen_or(gen_port6(cstate, (int)v, proto, dir), b); return b; } case Q_PORTRANGE: if (proto == Q_UDP) proto = IPPROTO_UDP; else if (proto == Q_TCP) proto = IPPROTO_TCP; else if (proto == Q_SCTP) proto = IPPROTO_SCTP; else if (proto == Q_DEFAULT) proto = PROTO_UNDEF; else bpf_error(cstate, "illegal qualifier of 'portrange'"); if (v > 65535) bpf_error(cstate, "illegal port number %u > 65535", v); { struct block *b; b = gen_portrange(cstate, (int)v, (int)v, proto, dir); gen_or(gen_portrange6(cstate, (int)v, (int)v, proto, dir), b); return b; } case Q_GATEWAY: bpf_error(cstate, "'gateway' requires a name"); /* NOTREACHED */ case Q_PROTO: return gen_proto(cstate, (int)v, proto, dir); case Q_PROTOCHAIN: return gen_protochain(cstate, (int)v, proto, dir); case Q_UNDEF: syntax(cstate); /* NOTREACHED */ default: abort(); /* NOTREACHED */ } /* NOTREACHED */ } #ifdef INET6 struct block * gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2, unsigned int masklen, struct qual q) { struct addrinfo *res; struct in6_addr *addr; struct in6_addr mask; struct block *b; u_int32_t *a, *m; if (s2) bpf_error(cstate, "no mask %s supported", s2); res = pcap_nametoaddrinfo(s1); if (!res) bpf_error(cstate, "invalid ip6 address %s", s1); cstate->ai = res; if (res->ai_next) bpf_error(cstate, "%s resolved to multiple address", s1); addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; if (sizeof(mask) * 8 < masklen) bpf_error(cstate, "mask length must be <= %u", (unsigned int)(sizeof(mask) * 8)); memset(&mask, 0, sizeof(mask)); memset(&mask, 0xff, masklen / 8); if (masklen % 8) { mask.s6_addr[masklen / 8] = (0xff << (8 - masklen % 8)) & 0xff; } a = (u_int32_t *)addr; m = (u_int32_t *)&mask; if ((a[0] & ~m[0]) || (a[1] & ~m[1]) || (a[2] & ~m[2]) || (a[3] & ~m[3])) { bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen); } switch (q.addr) { case Q_DEFAULT: case Q_HOST: if (masklen != 128) bpf_error(cstate, "Mask syntax for networks only"); /* FALLTHROUGH */ case Q_NET: b = gen_host6(cstate, addr, &mask, q.proto, q.dir, q.addr); cstate->ai = NULL; freeaddrinfo(res); return b; default: bpf_error(cstate, "invalid qualifier against IPv6 address"); /* NOTREACHED */ } return NULL; } #endif /*INET6*/ struct block * gen_ecode(compiler_state_t *cstate, const u_char *eaddr, struct qual q) { struct block *b, *tmp; if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: tmp = gen_prevlinkhdr_check(cstate); b = gen_ehostop(cstate, eaddr, (int)q.dir); if (tmp != NULL) gen_and(tmp, b); return b; case DLT_FDDI: return gen_fhostop(cstate, eaddr, (int)q.dir); case DLT_IEEE802: return gen_thostop(cstate, eaddr, (int)q.dir); case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: return gen_wlanhostop(cstate, eaddr, (int)q.dir); case DLT_IP_OVER_FC: return gen_ipfchostop(cstate, eaddr, (int)q.dir); default: bpf_error(cstate, "ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); break; } } bpf_error(cstate, "ethernet address used in non-ether expression"); /* NOTREACHED */ return NULL; } void sappend(s0, s1) struct slist *s0, *s1; { /* * This is definitely not the best way to do this, but the * lists will rarely get long. */ while (s0->next) s0 = s0->next; s0->next = s1; } static struct slist * xfer_to_x(compiler_state_t *cstate, struct arth *a) { struct slist *s; s = new_stmt(cstate, BPF_LDX|BPF_MEM); s->s.k = a->regno; return s; } static struct slist * xfer_to_a(compiler_state_t *cstate, struct arth *a) { struct slist *s; s = new_stmt(cstate, BPF_LD|BPF_MEM); s->s.k = a->regno; return s; } /* * Modify "index" to use the value stored into its register as an * offset relative to the beginning of the header for the protocol * "proto", and allocate a register and put an item "size" bytes long * (1, 2, or 4) at that offset into that register, making it the register * for "index". */ struct arth * gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size) { struct slist *s, *tmp; struct block *b; int regno = alloc_reg(cstate); free_reg(cstate, inst->regno); switch (size) { default: bpf_error(cstate, "data size must be 1, 2, or 4"); case 1: size = BPF_B; break; case 2: size = BPF_H; break; case 4: size = BPF_W; break; } switch (proto) { default: bpf_error(cstate, "unsupported index operation"); case Q_RADIO: /* * The offset is relative to the beginning of the packet * data, if we have a radio header. (If we don't, this * is an error.) */ if (cstate->linktype != DLT_IEEE802_11_RADIO_AVS && cstate->linktype != DLT_IEEE802_11_RADIO && cstate->linktype != DLT_PRISM_HEADER) bpf_error(cstate, "radio information not present in capture"); /* * Load into the X register the offset computed into the * register specified by "index". */ s = xfer_to_x(cstate, inst); /* * Load the item at that offset. */ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size); sappend(s, tmp); sappend(inst->s, s); break; case Q_LINK: /* * The offset is relative to the beginning of * the link-layer header. * * XXX - what about ATM LANE? Should the index be * relative to the beginning of the AAL5 frame, so * that 0 refers to the beginning of the LE Control * field, or relative to the beginning of the LAN * frame, so that 0 refers, for Ethernet LANE, to * the beginning of the destination address? */ s = gen_abs_offset_varpart(cstate, &cstate->off_linkhdr); /* * If "s" is non-null, it has code to arrange that the * X register contains the length of the prefix preceding * the link-layer header. Add to it the offset computed * into the register specified by "index", and move that * into the X register. Otherwise, just load into the X * register the offset computed into the register specified * by "index". */ if (s != NULL) { sappend(s, xfer_to_a(cstate, inst)); sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); } else s = xfer_to_x(cstate, inst); /* * Load the item at the sum of the offset we've put in the * X register and the offset of the start of the link * layer header (which is 0 if the radio header is * variable-length; that header length is what we put * into the X register and then added to the index). */ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size); tmp->s.k = cstate->off_linkhdr.constant_part; sappend(s, tmp); sappend(inst->s, s); break; case Q_IP: case Q_ARP: case Q_RARP: case Q_ATALK: case Q_DECNET: case Q_SCA: case Q_LAT: case Q_MOPRC: case Q_MOPDL: case Q_IPV6: /* * The offset is relative to the beginning of * the network-layer header. * XXX - are there any cases where we want * cstate->off_nl_nosnap? */ s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); /* * If "s" is non-null, it has code to arrange that the * X register contains the variable part of the offset * of the link-layer payload. Add to it the offset * computed into the register specified by "index", * and move that into the X register. Otherwise, just * load into the X register the offset computed into * the register specified by "index". */ if (s != NULL) { sappend(s, xfer_to_a(cstate, inst)); sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); } else s = xfer_to_x(cstate, inst); /* * Load the item at the sum of the offset we've put in the * X register, the offset of the start of the network * layer header from the beginning of the link-layer * payload, and the constant part of the offset of the * start of the link-layer payload. */ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size); tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; sappend(s, tmp); sappend(inst->s, s); /* * Do the computation only if the packet contains * the protocol in question. */ b = gen_proto_abbrev(cstate, proto); if (inst->b) gen_and(inst->b, b); inst->b = b; break; case Q_SCTP: case Q_TCP: case Q_UDP: case Q_ICMP: case Q_IGMP: case Q_IGRP: case Q_PIM: case Q_VRRP: case Q_CARP: /* * The offset is relative to the beginning of * the transport-layer header. * * Load the X register with the length of the IPv4 header * (plus the offset of the link-layer header, if it's * a variable-length header), in bytes. * * XXX - are there any cases where we want * cstate->off_nl_nosnap? * XXX - we should, if we're built with * IPv6 support, generate code to load either * IPv4, IPv6, or both, as appropriate. */ s = gen_loadx_iphdrlen(cstate); /* * The X register now contains the sum of the variable * part of the offset of the link-layer payload and the * length of the network-layer header. * * Load into the A register the offset relative to * the beginning of the transport layer header, * add the X register to that, move that to the * X register, and load with an offset from the * X register equal to the sum of the constant part of * the offset of the link-layer payload and the offset, * relative to the beginning of the link-layer payload, * of the network-layer header. */ sappend(s, xfer_to_a(cstate, inst)); sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); sappend(s, tmp = new_stmt(cstate, BPF_LD|BPF_IND|size)); tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; sappend(inst->s, s); /* * Do the computation only if the packet contains * the protocol in question - which is true only * if this is an IP datagram and is the first or * only fragment of that datagram. */ gen_and(gen_proto_abbrev(cstate, proto), b = gen_ipfrag(cstate)); if (inst->b) gen_and(inst->b, b); gen_and(gen_proto_abbrev(cstate, Q_IP), b); inst->b = b; break; case Q_ICMPV6: bpf_error(cstate, "IPv6 upper-layer protocol is not supported by proto[x]"); /*NOTREACHED*/ } inst->regno = regno; s = new_stmt(cstate, BPF_ST); s->s.k = regno; sappend(inst->s, s); return inst; } struct block * gen_relation(compiler_state_t *cstate, int code, struct arth *a0, struct arth *a1, int reversed) { struct slist *s0, *s1, *s2; struct block *b, *tmp; s0 = xfer_to_x(cstate, a1); s1 = xfer_to_a(cstate, a0); if (code == BPF_JEQ) { s2 = new_stmt(cstate, BPF_ALU|BPF_SUB|BPF_X); b = new_block(cstate, JMP(code)); sappend(s1, s2); } else b = new_block(cstate, BPF_JMP|code|BPF_X); if (reversed) gen_not(b); sappend(s0, s1); sappend(a1->s, s0); sappend(a0->s, a1->s); b->stmts = a0->s; free_reg(cstate, a0->regno); free_reg(cstate, a1->regno); /* 'and' together protocol checks */ if (a0->b) { if (a1->b) { gen_and(a0->b, tmp = a1->b); } else tmp = a0->b; } else tmp = a1->b; if (tmp) gen_and(tmp, b); return b; } struct arth * gen_loadlen(compiler_state_t *cstate) { int regno = alloc_reg(cstate); struct arth *a = (struct arth *)newchunk(cstate, sizeof(*a)); struct slist *s; s = new_stmt(cstate, BPF_LD|BPF_LEN); s->next = new_stmt(cstate, BPF_ST); s->next->s.k = regno; a->s = s; a->regno = regno; return a; } struct arth * gen_loadi(compiler_state_t *cstate, int val) { struct arth *a; struct slist *s; int reg; a = (struct arth *)newchunk(cstate, sizeof(*a)); reg = alloc_reg(cstate); s = new_stmt(cstate, BPF_LD|BPF_IMM); s->s.k = val; s->next = new_stmt(cstate, BPF_ST); s->next->s.k = reg; a->s = s; a->regno = reg; return a; } struct arth * gen_neg(compiler_state_t *cstate, struct arth *a) { struct slist *s; s = xfer_to_a(cstate, a); sappend(a->s, s); s = new_stmt(cstate, BPF_ALU|BPF_NEG); s->s.k = 0; sappend(a->s, s); s = new_stmt(cstate, BPF_ST); s->s.k = a->regno; sappend(a->s, s); return a; } struct arth * gen_arth(compiler_state_t *cstate, int code, struct arth *a0, struct arth *a1) { struct slist *s0, *s1, *s2; /* * Disallow division by, or modulus by, zero; we do this here * so that it gets done even if the optimizer is disabled. */ if (code == BPF_DIV) { if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0) bpf_error(cstate, "division by zero"); } else if (code == BPF_MOD) { if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0) bpf_error(cstate, "modulus by zero"); } s0 = xfer_to_x(cstate, a1); s1 = xfer_to_a(cstate, a0); s2 = new_stmt(cstate, BPF_ALU|BPF_X|code); sappend(s1, s2); sappend(s0, s1); sappend(a1->s, s0); sappend(a0->s, a1->s); free_reg(cstate, a0->regno); free_reg(cstate, a1->regno); s0 = new_stmt(cstate, BPF_ST); a0->regno = s0->s.k = alloc_reg(cstate); sappend(a0->s, s0); return a0; } /* * Initialize the table of used registers and the current register. */ static void init_regs(compiler_state_t *cstate) { cstate->curreg = 0; memset(cstate->regused, 0, sizeof cstate->regused); } /* * Return the next free register. */ static int alloc_reg(compiler_state_t *cstate) { int n = BPF_MEMWORDS; while (--n >= 0) { if (cstate->regused[cstate->curreg]) cstate->curreg = (cstate->curreg + 1) % BPF_MEMWORDS; else { cstate->regused[cstate->curreg] = 1; return cstate->curreg; } } bpf_error(cstate, "too many registers needed to evaluate expression"); /* NOTREACHED */ return 0; } /* * Return a register to the table so it can * be used later. */ static void free_reg(compiler_state_t *cstate, int n) { cstate->regused[n] = 0; } static struct block * gen_len(compiler_state_t *cstate, int jmp, int n) { struct slist *s; struct block *b; s = new_stmt(cstate, BPF_LD|BPF_LEN); b = new_block(cstate, JMP(jmp)); b->stmts = s; b->s.k = n; return b; } struct block * gen_greater(compiler_state_t *cstate, int n) { return gen_len(cstate, BPF_JGE, n); } /* * Actually, this is less than or equal. */ struct block * gen_less(compiler_state_t *cstate, int n) { struct block *b; b = gen_len(cstate, BPF_JGT, n); gen_not(b); return b; } /* * This is for "byte {idx} {op} {val}"; "idx" is treated as relative to * the beginning of the link-layer header. * XXX - that means you can't test values in the radiotap header, but * as that header is difficult if not impossible to parse generally * without a loop, that might not be a severe problem. A new keyword * "radio" could be added for that, although what you'd really want * would be a way of testing particular radio header values, which * would generate code appropriate to the radio header in question. */ struct block * gen_byteop(compiler_state_t *cstate, int op, int idx, int val) { struct block *b; struct slist *s; switch (op) { default: abort(); case '=': return gen_cmp(cstate, OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val); case '<': b = gen_cmp_lt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val); return b; case '>': b = gen_cmp_gt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val); return b; case '|': s = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_K); break; case '&': s = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); break; } s->s.k = val; b = new_block(cstate, JMP(BPF_JEQ)); b->stmts = s; gen_not(b); return b; } static const u_char abroadcast[] = { 0x0 }; struct block * gen_broadcast(compiler_state_t *cstate, int proto) { bpf_u_int32 hostmask; struct block *b0, *b1, *b2; static const u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; switch (proto) { case Q_DEFAULT: case Q_LINK: switch (cstate->linktype) { case DLT_ARCNET: case DLT_ARCNET_LINUX: return gen_ahostop(cstate, abroadcast, Q_DST); case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: b1 = gen_prevlinkhdr_check(cstate); b0 = gen_ehostop(cstate, ebroadcast, Q_DST); if (b1 != NULL) gen_and(b1, b0); return b0; case DLT_FDDI: return gen_fhostop(cstate, ebroadcast, Q_DST); case DLT_IEEE802: return gen_thostop(cstate, ebroadcast, Q_DST); case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: return gen_wlanhostop(cstate, ebroadcast, Q_DST); case DLT_IP_OVER_FC: return gen_ipfchostop(cstate, ebroadcast, Q_DST); default: bpf_error(cstate, "not a broadcast link"); } break; case Q_IP: /* * We treat a netmask of PCAP_NETMASK_UNKNOWN (0xffffffff) * as an indication that we don't know the netmask, and fail * in that case. */ if (cstate->netmask == PCAP_NETMASK_UNKNOWN) bpf_error(cstate, "netmask not known, so 'ip broadcast' not supported"); b0 = gen_linktype(cstate, ETHERTYPE_IP); hostmask = ~cstate->netmask; b1 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, (bpf_int32)0, hostmask); b2 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, (bpf_int32)(~0 & hostmask), hostmask); gen_or(b1, b2); gen_and(b0, b2); return b2; } bpf_error(cstate, "only link-layer/IP broadcast filters supported"); /* NOTREACHED */ return NULL; } /* * Generate code to test the low-order bit of a MAC address (that's * the bottom bit of the *first* byte). */ static struct block * gen_mac_multicast(compiler_state_t *cstate, int offset) { register struct block *b0; register struct slist *s; /* link[offset] & 1 != 0 */ s = gen_load_a(cstate, OR_LINKHDR, offset, BPF_B); b0 = new_block(cstate, JMP(BPF_JSET)); b0->s.k = 1; b0->stmts = s; return b0; } struct block * gen_multicast(compiler_state_t *cstate, int proto) { register struct block *b0, *b1, *b2; register struct slist *s; switch (proto) { case Q_DEFAULT: case Q_LINK: switch (cstate->linktype) { case DLT_ARCNET: case DLT_ARCNET_LINUX: /* all ARCnet multicasts use the same address */ return gen_ahostop(cstate, abroadcast, Q_DST); case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: b1 = gen_prevlinkhdr_check(cstate); /* ether[0] & 1 != 0 */ b0 = gen_mac_multicast(cstate, 0); if (b1 != NULL) gen_and(b1, b0); return b0; case DLT_FDDI: /* * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX * * XXX - was that referring to bit-order issues? */ /* fddi[1] & 1 != 0 */ return gen_mac_multicast(cstate, 1); case DLT_IEEE802: /* tr[2] & 1 != 0 */ return gen_mac_multicast(cstate, 2); case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: /* * Oh, yuk. * * For control frames, there is no DA. * * For management frames, DA is at an * offset of 4 from the beginning of * the packet. * * For data frames, DA is at an offset * of 4 from the beginning of the packet * if To DS is clear and at an offset of * 16 from the beginning of the packet * if To DS is set. */ /* * Generate the tests to be done for data frames. * * First, check for To DS set, i.e. "link[1] & 0x01". */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x01; /* To DS */ b1->stmts = s; /* * If To DS is set, the DA is at 16. */ b0 = gen_mac_multicast(cstate, 16); gen_and(b1, b0); /* * Now, check for To DS not set, i.e. check * "!(link[1] & 0x01)". */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x01; /* To DS */ b2->stmts = s; gen_not(b2); /* * If To DS is not set, the DA is at 4. */ b1 = gen_mac_multicast(cstate, 4); gen_and(b2, b1); /* * Now OR together the last two checks. That gives * the complete set of checks for data frames. */ gen_or(b1, b0); /* * Now check for a data frame. * I.e, check "link[0] & 0x08". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; /* * AND that with the checks done for data frames. */ gen_and(b1, b0); /* * If the high-order bit of the type value is 0, this * is a management frame. * I.e, check "!(link[0] & 0x08)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x08; b2->stmts = s; gen_not(b2); /* * For management frames, the DA is at 4. */ b1 = gen_mac_multicast(cstate, 4); gen_and(b2, b1); /* * OR that with the checks done for data frames. * That gives the checks done for management and * data frames. */ gen_or(b1, b0); /* * If the low-order bit of the type value is 1, * this is either a control frame or a frame * with a reserved type, and thus not a * frame with an SA. * * I.e., check "!(link[0] & 0x04)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x04; b1->stmts = s; gen_not(b1); /* * AND that with the checks for data and management * frames. */ gen_and(b1, b0); return b0; case DLT_IP_OVER_FC: b0 = gen_mac_multicast(cstate, 2); return b0; default: break; } /* Link not known to support multicasts */ break; case Q_IP: b0 = gen_linktype(cstate, ETHERTYPE_IP); b1 = gen_cmp_ge(cstate, OR_LINKPL, 16, BPF_B, (bpf_int32)224); gen_and(b0, b1); return b1; case Q_IPV6: b0 = gen_linktype(cstate, ETHERTYPE_IPV6); b1 = gen_cmp(cstate, OR_LINKPL, 24, BPF_B, (bpf_int32)255); gen_and(b0, b1); return b1; } bpf_error(cstate, "link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel"); /* NOTREACHED */ return NULL; } /* * Filter on inbound (dir == 0) or outbound (dir == 1) traffic. * Outbound traffic is sent by this machine, while inbound traffic is * sent by a remote machine (and may include packets destined for a * unicast or multicast link-layer address we are not subscribing to). * These are the same definitions implemented by pcap_setdirection(). * Capturing only unicast traffic destined for this host is probably * better accomplished using a higher-layer filter. */ struct block * gen_inbound(compiler_state_t *cstate, int dir) { register struct block *b0; /* * Only some data link types support inbound/outbound qualifiers. */ switch (cstate->linktype) { case DLT_SLIP: b0 = gen_relation(cstate, BPF_JEQ, gen_load(cstate, Q_LINK, gen_loadi(cstate, 0), 1), gen_loadi(cstate, 0), dir); break; case DLT_IPNET: if (dir) { /* match outgoing packets */ b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_OUTBOUND); } else { /* match incoming packets */ b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_INBOUND); } break; case DLT_LINUX_SLL: /* match outgoing packets */ b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_H, LINUX_SLL_OUTGOING); if (!dir) { /* to filter on inbound traffic, invert the match */ gen_not(b0); } break; #ifdef HAVE_NET_PFVAR_H case DLT_PFLOG: b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B, (bpf_int32)((dir == 0) ? PF_IN : PF_OUT)); break; #endif case DLT_PPP_PPPD: if (dir) { /* match outgoing packets */ b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_OUT); } else { /* match incoming packets */ b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_IN); } break; case DLT_JUNIPER_MFR: case DLT_JUNIPER_MLFR: case DLT_JUNIPER_MLPPP: case DLT_JUNIPER_ATM1: case DLT_JUNIPER_ATM2: case DLT_JUNIPER_PPPOE: case DLT_JUNIPER_PPPOE_ATM: case DLT_JUNIPER_GGSN: case DLT_JUNIPER_ES: case DLT_JUNIPER_MONITOR: case DLT_JUNIPER_SERVICES: case DLT_JUNIPER_ETHER: case DLT_JUNIPER_PPP: case DLT_JUNIPER_FRELAY: case DLT_JUNIPER_CHDLC: case DLT_JUNIPER_VP: case DLT_JUNIPER_ST: case DLT_JUNIPER_ISM: case DLT_JUNIPER_VS: case DLT_JUNIPER_SRX_E2E: case DLT_JUNIPER_FIBRECHANNEL: case DLT_JUNIPER_ATM_CEMIC: /* juniper flags (including direction) are stored * the byte after the 3-byte magic number */ if (dir) { /* match outgoing packets */ b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 0, 0x01); } else { /* match incoming packets */ b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 1, 0x01); } break; default: /* * If we have packet meta-data indicating a direction, * check it, otherwise give up as this link-layer type * has nothing in the packet data. */ #if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) /* * This is Linux with PF_PACKET support. * If this is a *live* capture, we can look at * special meta-data in the filter expression; * if it's a savefile, we can't. */ if (cstate->bpf_pcap->rfile != NULL) { /* We have a FILE *, so this is a savefile */ bpf_error(cstate, "inbound/outbound not supported on linktype %d when reading savefiles", cstate->linktype); b0 = NULL; /* NOTREACHED */ } /* match outgoing packets */ b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_PKTTYPE, BPF_H, PACKET_OUTGOING); if (!dir) { /* to filter on inbound traffic, invert the match */ gen_not(b0); } #else /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ bpf_error(cstate, "inbound/outbound not supported on linktype %d", cstate->linktype); b0 = NULL; /* NOTREACHED */ #endif /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ } return (b0); } #ifdef HAVE_NET_PFVAR_H /* PF firewall log matched interface */ struct block * gen_pf_ifname(compiler_state_t *cstate, const char *ifname) { struct block *b0; u_int len, off; if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "ifname supported only on PF linktype"); /* NOTREACHED */ } len = sizeof(((struct pfloghdr *)0)->ifname); off = offsetof(struct pfloghdr, ifname); if (strlen(ifname) >= len) { bpf_error(cstate, "ifname interface names can only be %d characters", len-1); /* NOTREACHED */ } b0 = gen_bcmp(cstate, OR_LINKHDR, off, strlen(ifname), (const u_char *)ifname); return (b0); } /* PF firewall log ruleset name */ struct block * gen_pf_ruleset(compiler_state_t *cstate, char *ruleset) { struct block *b0; if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "ruleset supported only on PF linktype"); /* NOTREACHED */ } if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) { bpf_error(cstate, "ruleset names can only be %ld characters", (long)(sizeof(((struct pfloghdr *)0)->ruleset) - 1)); /* NOTREACHED */ } b0 = gen_bcmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, ruleset), strlen(ruleset), (const u_char *)ruleset); return (b0); } /* PF firewall log rule number */ struct block * gen_pf_rnr(compiler_state_t *cstate, int rnr) { struct block *b0; if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "rnr supported only on PF linktype"); /* NOTREACHED */ } b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W, (bpf_int32)rnr); return (b0); } /* PF firewall log sub-rule number */ struct block * gen_pf_srnr(compiler_state_t *cstate, int srnr) { struct block *b0; if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "srnr supported only on PF linktype"); /* NOTREACHED */ } b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W, (bpf_int32)srnr); return (b0); } /* PF firewall log reason code */ struct block * gen_pf_reason(compiler_state_t *cstate, int reason) { struct block *b0; if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "reason supported only on PF linktype"); /* NOTREACHED */ } b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B, (bpf_int32)reason); return (b0); } /* PF firewall log action */ struct block * gen_pf_action(compiler_state_t *cstate, int action) { struct block *b0; if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "action supported only on PF linktype"); /* NOTREACHED */ } b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B, (bpf_int32)action); return (b0); } #else /* !HAVE_NET_PFVAR_H */ struct block * gen_pf_ifname(compiler_state_t *cstate, const char *ifname) { bpf_error(cstate, "libpcap was compiled without pf support"); /* NOTREACHED */ return (NULL); } struct block * gen_pf_ruleset(compiler_state_t *cstate, char *ruleset) { bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ return (NULL); } struct block * gen_pf_rnr(compiler_state_t *cstate, int rnr) { bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ return (NULL); } struct block * gen_pf_srnr(compiler_state_t *cstate, int srnr) { bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ return (NULL); } struct block * gen_pf_reason(compiler_state_t *cstate, int reason) { bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ return (NULL); } struct block * gen_pf_action(compiler_state_t *cstate, int action) { bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ return (NULL); } #endif /* HAVE_NET_PFVAR_H */ /* IEEE 802.11 wireless header */ struct block * gen_p80211_type(compiler_state_t *cstate, int type, int mask) { struct block *b0; switch (cstate->linktype) { case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, (bpf_int32)type, (bpf_int32)mask); break; default: bpf_error(cstate, "802.11 link-layer types supported only on 802.11"); /* NOTREACHED */ } return (b0); } struct block * gen_p80211_fcdir(compiler_state_t *cstate, int fcdir) { struct block *b0; switch (cstate->linktype) { case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: break; default: bpf_error(cstate, "frame direction supported only with 802.11 headers"); /* NOTREACHED */ } b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, (bpf_int32)fcdir, (bpf_u_int32)IEEE80211_FC1_DIR_MASK); return (b0); } struct block * gen_acode(compiler_state_t *cstate, const u_char *eaddr, struct qual q) { switch (cstate->linktype) { case DLT_ARCNET: case DLT_ARCNET_LINUX: if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) return (gen_ahostop(cstate, eaddr, (int)q.dir)); else { bpf_error(cstate, "ARCnet address used in non-arc expression"); /* NOTREACHED */ } break; default: bpf_error(cstate, "aid supported only on ARCnet"); /* NOTREACHED */ } bpf_error(cstate, "ARCnet address used in non-arc expression"); /* NOTREACHED */ return NULL; } static struct block * gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { register struct block *b0, *b1; switch (dir) { /* src comes first, different from Ethernet */ case Q_SRC: return gen_bcmp(cstate, OR_LINKHDR, 0, 1, eaddr); case Q_DST: return gen_bcmp(cstate, OR_LINKHDR, 1, 1, eaddr); case Q_AND: b0 = gen_ahostop(cstate, eaddr, Q_SRC); b1 = gen_ahostop(cstate, eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_ahostop(cstate, eaddr, Q_SRC); b1 = gen_ahostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' is only supported on 802.11"); break; case Q_ADDR2: bpf_error(cstate, "'addr2' is only supported on 802.11"); break; case Q_ADDR3: bpf_error(cstate, "'addr3' is only supported on 802.11"); break; case Q_ADDR4: bpf_error(cstate, "'addr4' is only supported on 802.11"); break; case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11"); break; case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11"); break; } abort(); /* NOTREACHED */ } #if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) static struct block * gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num) { struct block *b0, *b1; struct slist *s; /* generate new filter code based on extracting packet * metadata */ s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT; b0 = new_block(cstate, JMP(BPF_JEQ)); b0->stmts = s; b0->s.k = 1; if (vlan_num >= 0) { s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG; b1 = new_block(cstate, JMP(BPF_JEQ)); b1->stmts = s; b1->s.k = (bpf_int32) vlan_num; gen_and(b0,b1); b0 = b1; } return b0; } #endif static struct block * gen_vlan_no_bpf_extensions(compiler_state_t *cstate, int vlan_num) { struct block *b0, *b1; /* check for VLAN, including QinQ */ b0 = gen_linktype(cstate, ETHERTYPE_8021Q); b1 = gen_linktype(cstate, ETHERTYPE_8021AD); gen_or(b0,b1); b0 = b1; b1 = gen_linktype(cstate, ETHERTYPE_8021QINQ); gen_or(b0,b1); b0 = b1; /* If a specific VLAN is requested, check VLAN id */ if (vlan_num >= 0) { b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, (bpf_int32)vlan_num, 0x0fff); gen_and(b0, b1); b0 = b1; } /* * The payload follows the full header, including the * VLAN tags, so skip past this VLAN tag. */ cstate->off_linkpl.constant_part += 4; /* * The link-layer type information follows the VLAN tags, so * skip past this VLAN tag. */ cstate->off_linktype.constant_part += 4; return b0; } /* * support IEEE 802.1Q VLAN trunk over ethernet */ struct block * gen_vlan(compiler_state_t *cstate, int vlan_num) { struct block *b0; /* can't check for VLAN-encapsulated packets inside MPLS */ if (cstate->label_stack_depth > 0) bpf_error(cstate, "no VLAN match after MPLS"); /* * Check for a VLAN packet, and then change the offsets to point * to the type and data fields within the VLAN packet. Just * increment the offsets, so that we can support a hierarchy, e.g. * "vlan 300 && vlan 200" to capture VLAN 200 encapsulated within * VLAN 100. * * XXX - this is a bit of a kludge. If we were to split the * compiler into a parser that parses an expression and * generates an expression tree, and a code generator that * takes an expression tree (which could come from our * parser or from some other parser) and generates BPF code, * we could perhaps make the offsets parameters of routines * and, in the handler for an "AND" node, pass to subnodes * other than the VLAN node the adjusted offsets. * * This would mean that "vlan" would, instead of changing the * behavior of *all* tests after it, change only the behavior * of tests ANDed with it. That would change the documented * semantics of "vlan", which might break some expressions. * However, it would mean that "(vlan and ip) or ip" would check * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than * checking only for VLAN-encapsulated IP, so that could still * be considered worth doing; it wouldn't break expressions * that are of the form "vlan and ..." or "vlan N and ...", * which I suspect are the most common expressions involving * "vlan". "vlan or ..." doesn't necessarily do what the user * would really want, now, as all the "or ..." tests would * be done assuming a VLAN, even though the "or" could be viewed * as meaning "or, if this isn't a VLAN packet...". */ switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: #if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) /* Verify that this is the outer part of the packet and * not encapsulated somehow. */ if (cstate->vlan_stack_depth == 0 && !cstate->off_linkhdr.is_variable && cstate->off_linkhdr.constant_part == cstate->off_outermostlinkhdr.constant_part) { /* * Do we need special VLAN handling? */ if (cstate->bpf_pcap->bpf_codegen_flags & BPF_SPECIAL_VLAN_HANDLING) b0 = gen_vlan_bpf_extensions(cstate, vlan_num); else b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num); } else #endif b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num); break; case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num); break; default: bpf_error(cstate, "no VLAN support for data link type %d", cstate->linktype); /*NOTREACHED*/ } cstate->vlan_stack_depth++; return (b0); } /* * support for MPLS */ struct block * gen_mpls(compiler_state_t *cstate, int label_num) { struct block *b0, *b1; if (cstate->label_stack_depth > 0) { /* just match the bottom-of-stack bit clear */ b0 = gen_mcmp(cstate, OR_PREVMPLSHDR, 2, BPF_B, 0, 0x01); } else { /* * We're not in an MPLS stack yet, so check the link-layer * type against MPLS. */ switch (cstate->linktype) { case DLT_C_HDLC: /* fall through */ case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: b0 = gen_linktype(cstate, ETHERTYPE_MPLS); break; case DLT_PPP: b0 = gen_linktype(cstate, PPP_MPLS_UCAST); break; /* FIXME add other DLT_s ... * for Frame-Relay/and ATM this may get messy due to SNAP headers * leave it for now */ default: bpf_error(cstate, "no MPLS support for data link type %d", cstate->linktype); b0 = NULL; /*NOTREACHED*/ break; } } /* If a specific MPLS label is requested, check it */ if (label_num >= 0) { label_num = label_num << 12; /* label is shifted 12 bits on the wire */ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, (bpf_int32)label_num, 0xfffff000); /* only compare the first 20 bits */ gen_and(b0, b1); b0 = b1; } /* * Change the offsets to point to the type and data fields within * the MPLS packet. Just increment the offsets, so that we * can support a hierarchy, e.g. "mpls 100000 && mpls 1024" to * capture packets with an outer label of 100000 and an inner * label of 1024. * * Increment the MPLS stack depth as well; this indicates that * we're checking MPLS-encapsulated headers, to make sure higher * level code generators don't try to match against IP-related * protocols such as Q_ARP, Q_RARP etc. * * XXX - this is a bit of a kludge. See comments in gen_vlan(). */ cstate->off_nl_nosnap += 4; cstate->off_nl += 4; cstate->label_stack_depth++; return (b0); } /* * Support PPPOE discovery and session. */ struct block * gen_pppoed(compiler_state_t *cstate) { /* check for PPPoE discovery */ return gen_linktype(cstate, (bpf_int32)ETHERTYPE_PPPOED); } struct block * gen_pppoes(compiler_state_t *cstate, int sess_num) { struct block *b0, *b1; /* * Test against the PPPoE session link-layer type. */ b0 = gen_linktype(cstate, (bpf_int32)ETHERTYPE_PPPOES); /* If a specific session is requested, check PPPoE session id */ if (sess_num >= 0) { b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, (bpf_int32)sess_num, 0x0000ffff); gen_and(b0, b1); b0 = b1; } /* * Change the offsets to point to the type and data fields within * the PPP packet, and note that this is PPPoE rather than * raw PPP. * * XXX - this is a bit of a kludge. If we were to split the * compiler into a parser that parses an expression and * generates an expression tree, and a code generator that * takes an expression tree (which could come from our * parser or from some other parser) and generates BPF code, * we could perhaps make the offsets parameters of routines * and, in the handler for an "AND" node, pass to subnodes * other than the PPPoE node the adjusted offsets. * * This would mean that "pppoes" would, instead of changing the * behavior of *all* tests after it, change only the behavior * of tests ANDed with it. That would change the documented * semantics of "pppoes", which might break some expressions. * However, it would mean that "(pppoes and ip) or ip" would check * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than * checking only for VLAN-encapsulated IP, so that could still * be considered worth doing; it wouldn't break expressions * that are of the form "pppoes and ..." which I suspect are the * most common expressions involving "pppoes". "pppoes or ..." * doesn't necessarily do what the user would really want, now, * as all the "or ..." tests would be done assuming PPPoE, even * though the "or" could be viewed as meaning "or, if this isn't * a PPPoE packet...". * * The "network-layer" protocol is PPPoE, which has a 6-byte * PPPoE header, followed by a PPP packet. * * There is no HDLC encapsulation for the PPP packet (it's * encapsulated in PPPoES instead), so the link-layer type * starts at the first byte of the PPP packet. For PPPoE, * that offset is relative to the beginning of the total * link-layer payload, including any 802.2 LLC header, so * it's 6 bytes past cstate->off_nl. */ PUSH_LINKHDR(cstate, DLT_PPP, cstate->off_linkpl.is_variable, cstate->off_linkpl.constant_part + cstate->off_nl + 6, /* 6 bytes past the PPPoE header */ cstate->off_linkpl.reg); cstate->off_linktype = cstate->off_linkhdr; cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 2; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ return b0; } /* Check that this is Geneve and the VNI is correct if * specified. Parameterized to handle both IPv4 and IPv6. */ static struct block * gen_geneve_check(compiler_state_t *cstate, struct block *(*gen_portfn)(compiler_state_t *, int, int, int), enum e_offrel offrel, int vni) { struct block *b0, *b1; b0 = gen_portfn(cstate, GENEVE_PORT, IPPROTO_UDP, Q_DST); /* Check that we are operating on version 0. Otherwise, we * can't decode the rest of the fields. The version is 2 bits * in the first byte of the Geneve header. */ b1 = gen_mcmp(cstate, offrel, 8, BPF_B, (bpf_int32)0, 0xc0); gen_and(b0, b1); b0 = b1; if (vni >= 0) { vni <<= 8; /* VNI is in the upper 3 bytes */ b1 = gen_mcmp(cstate, offrel, 12, BPF_W, (bpf_int32)vni, 0xffffff00); gen_and(b0, b1); b0 = b1; } return b0; } /* The IPv4 and IPv6 Geneve checks need to do two things: * - Verify that this actually is Geneve with the right VNI. * - Place the IP header length (plus variable link prefix if * needed) into register A to be used later to compute * the inner packet offsets. */ static struct block * gen_geneve4(compiler_state_t *cstate, int vni) { struct block *b0, *b1; struct slist *s, *s1; b0 = gen_geneve_check(cstate, gen_port, OR_TRAN_IPV4, vni); /* Load the IP header length into A. */ s = gen_loadx_iphdrlen(cstate); s1 = new_stmt(cstate, BPF_MISC|BPF_TXA); sappend(s, s1); /* Forcibly append these statements to the true condition * of the protocol check by creating a new block that is * always true and ANDing them. */ b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X); b1->stmts = s; b1->s.k = 0; gen_and(b0, b1); return b1; } static struct block * gen_geneve6(compiler_state_t *cstate, int vni) { struct block *b0, *b1; struct slist *s, *s1; b0 = gen_geneve_check(cstate, gen_port6, OR_TRAN_IPV6, vni); /* Load the IP header length. We need to account for a * variable length link prefix if there is one. */ s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); if (s) { s1 = new_stmt(cstate, BPF_LD|BPF_IMM); s1->s.k = 40; sappend(s, s1); s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X); s1->s.k = 0; sappend(s, s1); } else { s = new_stmt(cstate, BPF_LD|BPF_IMM); s->s.k = 40; } /* Forcibly append these statements to the true condition * of the protocol check by creating a new block that is * always true and ANDing them. */ s1 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s, s1); b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X); b1->stmts = s; b1->s.k = 0; gen_and(b0, b1); return b1; } /* We need to store three values based on the Geneve header:: * - The offset of the linktype. * - The offset of the end of the Geneve header. * - The offset of the end of the encapsulated MAC header. */ static struct slist * gen_geneve_offsets(compiler_state_t *cstate) { struct slist *s, *s1, *s_proto; /* First we need to calculate the offset of the Geneve header * itself. This is composed of the IP header previously calculated * (include any variable link prefix) and stored in A plus the * fixed sized headers (fixed link prefix, MAC length, and UDP * header). */ s = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 8; /* Stash this in X since we'll need it later. */ s1 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s, s1); /* The EtherType in Geneve is 2 bytes in. Calculate this and * store it. */ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s1->s.k = 2; sappend(s, s1); cstate->off_linktype.reg = alloc_reg(cstate); cstate->off_linktype.is_variable = 1; cstate->off_linktype.constant_part = 0; s1 = new_stmt(cstate, BPF_ST); s1->s.k = cstate->off_linktype.reg; sappend(s, s1); /* Load the Geneve option length and mask and shift to get the * number of bytes. It is stored in the first byte of the Geneve * header. */ s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s1->s.k = 0; sappend(s, s1); s1 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); s1->s.k = 0x3f; sappend(s, s1); s1 = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K); s1->s.k = 4; sappend(s, s1); /* Add in the rest of the Geneve base header. */ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s1->s.k = 8; sappend(s, s1); /* Add the Geneve header length to its offset and store. */ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X); s1->s.k = 0; sappend(s, s1); /* Set the encapsulated type as Ethernet. Even though we may * not actually have Ethernet inside there are two reasons this * is useful: * - The linktype field is always in EtherType format regardless * of whether it is in Geneve or an inner Ethernet frame. * - The only link layer that we have specific support for is * Ethernet. We will confirm that the packet actually is * Ethernet at runtime before executing these checks. */ PUSH_LINKHDR(cstate, DLT_EN10MB, 1, 0, alloc_reg(cstate)); s1 = new_stmt(cstate, BPF_ST); s1->s.k = cstate->off_linkhdr.reg; sappend(s, s1); /* Calculate whether we have an Ethernet header or just raw IP/ * MPLS/etc. If we have Ethernet, advance the end of the MAC offset * and linktype by 14 bytes so that the network header can be found * seamlessly. Otherwise, keep what we've calculated already. */ /* We have a bare jmp so we can't use the optimizer. */ cstate->no_optimize = 1; /* Load the EtherType in the Geneve header, 2 bytes in. */ s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_H); s1->s.k = 2; sappend(s, s1); /* Load X with the end of the Geneve header. */ s1 = new_stmt(cstate, BPF_LDX|BPF_MEM); s1->s.k = cstate->off_linkhdr.reg; sappend(s, s1); /* Check if the EtherType is Transparent Ethernet Bridging. At the * end of this check, we should have the total length in X. In * the non-Ethernet case, it's already there. */ s_proto = new_stmt(cstate, JMP(BPF_JEQ)); s_proto->s.k = ETHERTYPE_TEB; sappend(s, s_proto); s1 = new_stmt(cstate, BPF_MISC|BPF_TXA); sappend(s, s1); s_proto->s.jt = s1; /* Since this is Ethernet, use the EtherType of the payload * directly as the linktype. Overwrite what we already have. */ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s1->s.k = 12; sappend(s, s1); s1 = new_stmt(cstate, BPF_ST); s1->s.k = cstate->off_linktype.reg; sappend(s, s1); /* Advance two bytes further to get the end of the Ethernet * header. */ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s1->s.k = 2; sappend(s, s1); /* Move the result to X. */ s1 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s, s1); /* Store the final result of our linkpl calculation. */ cstate->off_linkpl.reg = alloc_reg(cstate); cstate->off_linkpl.is_variable = 1; cstate->off_linkpl.constant_part = 0; s1 = new_stmt(cstate, BPF_STX); s1->s.k = cstate->off_linkpl.reg; sappend(s, s1); s_proto->s.jf = s1; cstate->off_nl = 0; return s; } /* Check to see if this is a Geneve packet. */ struct block * gen_geneve(compiler_state_t *cstate, int vni) { struct block *b0, *b1; struct slist *s; b0 = gen_geneve4(cstate, vni); b1 = gen_geneve6(cstate, vni); gen_or(b0, b1); b0 = b1; /* Later filters should act on the payload of the Geneve frame, * update all of the header pointers. Attach this code so that * it gets executed in the event that the Geneve filter matches. */ s = gen_geneve_offsets(cstate); b1 = gen_true(cstate); sappend(s, b1->stmts); b1->stmts = s; gen_and(b0, b1); cstate->is_geneve = 1; return b1; } /* Check that the encapsulated frame has a link layer header * for Ethernet filters. */ static struct block * gen_geneve_ll_check(compiler_state_t *cstate) { struct block *b0; struct slist *s, *s1; /* The easiest way to see if there is a link layer present * is to check if the link layer header and payload are not * the same. */ /* Geneve always generates pure variable offsets so we can * compare only the registers. */ s = new_stmt(cstate, BPF_LD|BPF_MEM); s->s.k = cstate->off_linkhdr.reg; s1 = new_stmt(cstate, BPF_LDX|BPF_MEM); s1->s.k = cstate->off_linkpl.reg; sappend(s, s1); b0 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X); b0->stmts = s; b0->s.k = 0; gen_not(b0); return b0; } struct block * gen_atmfield_code(compiler_state_t *cstate, int atmfield, bpf_int32 jvalue, bpf_u_int32 jtype, int reverse) { struct block *b0; switch (atmfield) { case A_VPI: if (!cstate->is_atm) bpf_error(cstate, "'vpi' supported only on raw ATM"); if (cstate->off_vpi == (u_int)-1) abort(); b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B, 0xffffffff, jtype, reverse, jvalue); break; case A_VCI: if (!cstate->is_atm) bpf_error(cstate, "'vci' supported only on raw ATM"); if (cstate->off_vci == (u_int)-1) abort(); b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H, 0xffffffff, jtype, reverse, jvalue); break; case A_PROTOTYPE: if (cstate->off_proto == (u_int)-1) abort(); /* XXX - this isn't on FreeBSD */ b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0x0f, jtype, reverse, jvalue); break; case A_MSGTYPE: if (cstate->off_payload == (u_int)-1) abort(); b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_payload + MSG_TYPE_POS, BPF_B, 0xffffffff, jtype, reverse, jvalue); break; case A_CALLREFTYPE: if (!cstate->is_atm) bpf_error(cstate, "'callref' supported only on raw ATM"); if (cstate->off_proto == (u_int)-1) abort(); b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0xffffffff, jtype, reverse, jvalue); break; default: abort(); } return b0; } struct block * gen_atmtype_abbrev(compiler_state_t *cstate, int type) { struct block *b0, *b1; switch (type) { case A_METAC: /* Get all packets in Meta signalling Circuit */ if (!cstate->is_atm) bpf_error(cstate, "'metac' supported only on raw ATM"); b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); b1 = gen_atmfield_code(cstate, A_VCI, 1, BPF_JEQ, 0); gen_and(b0, b1); break; case A_BCC: /* Get all packets in Broadcast Circuit*/ if (!cstate->is_atm) bpf_error(cstate, "'bcc' supported only on raw ATM"); b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); b1 = gen_atmfield_code(cstate, A_VCI, 2, BPF_JEQ, 0); gen_and(b0, b1); break; case A_OAMF4SC: /* Get all cells in Segment OAM F4 circuit*/ if (!cstate->is_atm) bpf_error(cstate, "'oam4sc' supported only on raw ATM"); b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); b1 = gen_atmfield_code(cstate, A_VCI, 3, BPF_JEQ, 0); gen_and(b0, b1); break; case A_OAMF4EC: /* Get all cells in End-to-End OAM F4 Circuit*/ if (!cstate->is_atm) bpf_error(cstate, "'oam4ec' supported only on raw ATM"); b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); b1 = gen_atmfield_code(cstate, A_VCI, 4, BPF_JEQ, 0); gen_and(b0, b1); break; case A_SC: /* Get all packets in connection Signalling Circuit */ if (!cstate->is_atm) bpf_error(cstate, "'sc' supported only on raw ATM"); b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); b1 = gen_atmfield_code(cstate, A_VCI, 5, BPF_JEQ, 0); gen_and(b0, b1); break; case A_ILMIC: /* Get all packets in ILMI Circuit */ if (!cstate->is_atm) bpf_error(cstate, "'ilmic' supported only on raw ATM"); b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); b1 = gen_atmfield_code(cstate, A_VCI, 16, BPF_JEQ, 0); gen_and(b0, b1); break; case A_LANE: /* Get all LANE packets */ if (!cstate->is_atm) bpf_error(cstate, "'lane' supported only on raw ATM"); b1 = gen_atmfield_code(cstate, A_PROTOTYPE, PT_LANE, BPF_JEQ, 0); /* * Arrange that all subsequent tests assume LANE * rather than LLC-encapsulated packets, and set * the offsets appropriately for LANE-encapsulated * Ethernet. * * We assume LANE means Ethernet, not Token Ring. */ PUSH_LINKHDR(cstate, DLT_EN10MB, 0, cstate->off_payload + 2, /* Ethernet header */ -1); cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12; cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* Ethernet */ cstate->off_nl = 0; /* Ethernet II */ cstate->off_nl_nosnap = 3; /* 802.3+802.2 */ break; case A_LLC: /* Get all LLC-encapsulated packets */ if (!cstate->is_atm) bpf_error(cstate, "'llc' supported only on raw ATM"); b1 = gen_atmfield_code(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); cstate->linktype = cstate->prevlinktype; break; default: abort(); } return b1; } /* * Filtering for MTP2 messages based on li value * FISU, length is null * LSSU, length is 1 or 2 * MSU, length is 3 or more * For MTP2_HSL, sequences are on 2 bytes, and length on 9 bits */ struct block * gen_mtp2type_abbrev(compiler_state_t *cstate, int type) { struct block *b0, *b1; switch (type) { case M_FISU: if ( (cstate->linktype != DLT_MTP2) && (cstate->linktype != DLT_ERF) && (cstate->linktype != DLT_MTP2_WITH_PHDR) ) bpf_error(cstate, "'fisu' supported only on MTP2"); /* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JEQ, 0, 0); break; case M_LSSU: if ( (cstate->linktype != DLT_MTP2) && (cstate->linktype != DLT_ERF) && (cstate->linktype != DLT_MTP2_WITH_PHDR) ) bpf_error(cstate, "'lssu' supported only on MTP2"); b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JGT, 1, 2); b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JGT, 0, 0); gen_and(b1, b0); break; case M_MSU: if ( (cstate->linktype != DLT_MTP2) && (cstate->linktype != DLT_ERF) && (cstate->linktype != DLT_MTP2_WITH_PHDR) ) bpf_error(cstate, "'msu' supported only on MTP2"); b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JGT, 0, 2); break; case MH_FISU: if ( (cstate->linktype != DLT_MTP2) && (cstate->linktype != DLT_ERF) && (cstate->linktype != DLT_MTP2_WITH_PHDR) ) bpf_error(cstate, "'hfisu' supported only on MTP2_HSL"); /* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JEQ, 0, 0); break; case MH_LSSU: if ( (cstate->linktype != DLT_MTP2) && (cstate->linktype != DLT_ERF) && (cstate->linktype != DLT_MTP2_WITH_PHDR) ) bpf_error(cstate, "'hlssu' supported only on MTP2_HSL"); b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JGT, 1, 0x0100); b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JGT, 0, 0); gen_and(b1, b0); break; case MH_MSU: if ( (cstate->linktype != DLT_MTP2) && (cstate->linktype != DLT_ERF) && (cstate->linktype != DLT_MTP2_WITH_PHDR) ) bpf_error(cstate, "'hmsu' supported only on MTP2_HSL"); b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JGT, 0, 0x0100); break; default: abort(); } return b0; } struct block * gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue, bpf_u_int32 jtype, int reverse) { struct block *b0; bpf_u_int32 val1 , val2 , val3; u_int newoff_sio = cstate->off_sio; u_int newoff_opc = cstate->off_opc; u_int newoff_dpc = cstate->off_dpc; u_int newoff_sls = cstate->off_sls; switch (mtp3field) { case MH_SIO: newoff_sio += 3; /* offset for MTP2_HSL */ /* FALLTHROUGH */ case M_SIO: if (cstate->off_sio == (u_int)-1) bpf_error(cstate, "'sio' supported only on SS7"); /* sio coded on 1 byte so max value 255 */ if(jvalue > 255) bpf_error(cstate, "sio value %u too big; max value = 255", jvalue); b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, 0xffffffff, (u_int)jtype, reverse, (u_int)jvalue); break; case MH_OPC: newoff_opc+=3; case M_OPC: if (cstate->off_opc == (u_int)-1) bpf_error(cstate, "'opc' supported only on SS7"); /* opc coded on 14 bits so max value 16383 */ if (jvalue > 16383) bpf_error(cstate, "opc value %u too big; max value = 16383", jvalue); /* the following instructions are made to convert jvalue * to the form used to write opc in an ss7 message*/ val1 = jvalue & 0x00003c00; val1 = val1 >>10; val2 = jvalue & 0x000003fc; val2 = val2 <<6; val3 = jvalue & 0x00000003; val3 = val3 <<22; jvalue = val1 + val2 + val3; b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0f, (u_int)jtype, reverse, (u_int)jvalue); break; case MH_DPC: newoff_dpc += 3; /* FALLTHROUGH */ case M_DPC: if (cstate->off_dpc == (u_int)-1) bpf_error(cstate, "'dpc' supported only on SS7"); /* dpc coded on 14 bits so max value 16383 */ if (jvalue > 16383) bpf_error(cstate, "dpc value %u too big; max value = 16383", jvalue); /* the following instructions are made to convert jvalue * to the forme used to write dpc in an ss7 message*/ val1 = jvalue & 0x000000ff; val1 = val1 << 24; val2 = jvalue & 0x00003f00; val2 = val2 << 8; jvalue = val1 + val2; b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000, (u_int)jtype, reverse, (u_int)jvalue); break; case MH_SLS: newoff_sls+=3; case M_SLS: if (cstate->off_sls == (u_int)-1) bpf_error(cstate, "'sls' supported only on SS7"); /* sls coded on 4 bits so max value 15 */ if (jvalue > 15) bpf_error(cstate, "sls value %u too big; max value = 15", jvalue); /* the following instruction is made to convert jvalue * to the forme used to write sls in an ss7 message*/ jvalue = jvalue << 4; b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B, 0xf0, (u_int)jtype,reverse, (u_int)jvalue); break; default: abort(); } return b0; } static struct block * gen_msg_abbrev(compiler_state_t *cstate, int type) { struct block *b1; /* * Q.2931 signalling protocol messages for handling virtual circuits * establishment and teardown */ switch (type) { case A_SETUP: b1 = gen_atmfield_code(cstate, A_MSGTYPE, SETUP, BPF_JEQ, 0); break; case A_CALLPROCEED: b1 = gen_atmfield_code(cstate, A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0); break; case A_CONNECT: b1 = gen_atmfield_code(cstate, A_MSGTYPE, CONNECT, BPF_JEQ, 0); break; case A_CONNECTACK: b1 = gen_atmfield_code(cstate, A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0); break; case A_RELEASE: b1 = gen_atmfield_code(cstate, A_MSGTYPE, RELEASE, BPF_JEQ, 0); break; case A_RELEASE_DONE: b1 = gen_atmfield_code(cstate, A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0); break; default: abort(); } return b1; } struct block * gen_atmmulti_abbrev(compiler_state_t *cstate, int type) { struct block *b0, *b1; switch (type) { case A_OAM: if (!cstate->is_atm) bpf_error(cstate, "'oam' supported only on raw ATM"); b1 = gen_atmmulti_abbrev(cstate, A_OAMF4); break; case A_OAMF4: if (!cstate->is_atm) bpf_error(cstate, "'oamf4' supported only on raw ATM"); /* OAM F4 type */ b0 = gen_atmfield_code(cstate, A_VCI, 3, BPF_JEQ, 0); b1 = gen_atmfield_code(cstate, A_VCI, 4, BPF_JEQ, 0); gen_or(b0, b1); b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); gen_and(b0, b1); break; case A_CONNECTMSG: /* * Get Q.2931 signalling messages for switched * virtual connection */ if (!cstate->is_atm) bpf_error(cstate, "'connectmsg' supported only on raw ATM"); b0 = gen_msg_abbrev(cstate, A_SETUP); b1 = gen_msg_abbrev(cstate, A_CALLPROCEED); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_CONNECT); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_CONNECTACK); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_RELEASE); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE); gen_or(b0, b1); b0 = gen_atmtype_abbrev(cstate, A_SC); gen_and(b0, b1); break; case A_METACONNECT: if (!cstate->is_atm) bpf_error(cstate, "'metaconnect' supported only on raw ATM"); b0 = gen_msg_abbrev(cstate, A_SETUP); b1 = gen_msg_abbrev(cstate, A_CALLPROCEED); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_CONNECT); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_RELEASE); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE); gen_or(b0, b1); b0 = gen_atmtype_abbrev(cstate, A_METAC); gen_and(b0, b1); break; default: abort(); } return b1; } libpcap-1.8.1/cmake/0000755000026300017510000000000013003775545012347 5ustar mcrmcrlibpcap-1.8.1/cmake/preconfigure.cmake0000644000026300017510000000450013003771737016037 0ustar mcrmcrif( NOT LIBPCAP_PRECONFIGURED ) set( LIBPCAP_PRECONFIGURED TRUE ) ################################################################### # Parameters ################################################################### option (USE_STATIC_RT "Use static Runtime" ON) ###################################### # Project setings ###################################### add_definitions( -DBUILDING_PCAP ) if( MSVC ) add_definitions( -D__STDC__ ) add_definitions( -D_CRT_SECURE_NO_WARNINGS ) add_definitions( "-D_U_=" ) elseif( CMAKE_COMPILER_IS_GNUCXX ) add_definitions( "-D_U_=__attribute__((unused))" ) else(MSVC) add_definitions( "-D_U_=" ) endif( MSVC ) if (USE_STATIC_RT) MESSAGE( STATUS "Use STATIC runtime" ) if( MSVC ) set (CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MT") set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT") set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") set (CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MT") set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MT") set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") endif( MSVC ) else (USE_STATIC_RT) MESSAGE( STATUS "Use DYNAMIC runtime" ) if( MSVC ) set (CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD") set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MD") set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd") set (CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MD") set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MD") set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD") set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MDd") endif( MSVC ) endif (USE_STATIC_RT) endif( NOT LIBPCAP_PRECONFIGURED ) libpcap-1.8.1/inet.c0000644000026300017510000002474413003771737012404 0ustar mcrmcr/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ /* * Copyright (c) 1994, 1995, 1996, 1997, 1998 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef _WIN32 #include #else /* _WIN32 */ #include #ifndef MSDOS #include #endif #include #include #ifdef HAVE_SYS_SOCKIO_H #include #endif struct mbuf; /* Squelch compiler warnings on some platforms for */ struct rtentry; /* declarations in */ #include #include #endif /* _WIN32 */ #include #include #include #include #include #if !defined(_WIN32) && !defined(__BORLANDC__) #include #endif /* !_WIN32 && !__BORLANDC__ */ #include "pcap-int.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #if !defined(_WIN32) && !defined(MSDOS) /* * Return the name of a network interface attached to the system, or NULL * if none can be found. The interface must be configured up; the * lowest unit number is preferred; loopback is ignored. */ char * pcap_lookupdev(errbuf) register char *errbuf; { pcap_if_t *alldevs; /* for old BSD systems, including bsdi3 */ #ifndef IF_NAMESIZE #define IF_NAMESIZE IFNAMSIZ #endif static char device[IF_NAMESIZE + 1]; char *ret; if (pcap_findalldevs(&alldevs, errbuf) == -1) return (NULL); if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) { /* * There are no devices on the list, or the first device * on the list is a loopback device, which means there * are no non-loopback devices on the list. This means * we can't return any device. * * XXX - why not return a loopback device? If we can't * capture on it, it won't be on the list, and if it's * on the list, there aren't any non-loopback devices, * so why not just supply it as the default device? */ (void)strlcpy(errbuf, "no suitable device found", PCAP_ERRBUF_SIZE); ret = NULL; } else { /* * Return the name of the first device on the list. */ (void)strlcpy(device, alldevs->name, sizeof(device)); ret = device; } pcap_freealldevs(alldevs); return (ret); } int pcap_lookupnet(device, netp, maskp, errbuf) register const char *device; register bpf_u_int32 *netp, *maskp; register char *errbuf; { register int fd; register struct sockaddr_in *sin4; struct ifreq ifr; /* * The pseudo-device "any" listens on all interfaces and therefore * has the network address and -mask "0.0.0.0" therefore catching * all traffic. Using NULL for the interface is the same as "any". */ if (!device || strcmp(device, "any") == 0 #ifdef HAVE_DAG_API || strstr(device, "dag") != NULL #endif #ifdef HAVE_SEPTEL_API || strstr(device, "septel") != NULL #endif #ifdef PCAP_SUPPORT_BT || strstr(device, "bluetooth") != NULL #endif #ifdef PCAP_SUPPORT_USB || strstr(device, "usbmon") != NULL #endif #ifdef HAVE_SNF_API || strstr(device, "snf") != NULL #endif ) { *netp = *maskp = 0; return 0; } fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); return (-1); } memset(&ifr, 0, sizeof(ifr)); #ifdef linux /* XXX Work around Linux kernel bug */ ifr.ifr_addr.sa_family = AF_INET; #endif (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { if (errno == EADDRNOTAVAIL) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: no IPv4 address assigned", device); } else { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFADDR: %s: %s", device, pcap_strerror(errno)); } (void)close(fd); return (-1); } sin4 = (struct sockaddr_in *)&ifr.ifr_addr; *netp = sin4->sin_addr.s_addr; memset(&ifr, 0, sizeof(ifr)); #ifdef linux /* XXX Work around Linux kernel bug */ ifr.ifr_addr.sa_family = AF_INET; #endif (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno)); (void)close(fd); return (-1); } (void)close(fd); *maskp = sin4->sin_addr.s_addr; if (*maskp == 0) { if (IN_CLASSA(*netp)) *maskp = IN_CLASSA_NET; else if (IN_CLASSB(*netp)) *maskp = IN_CLASSB_NET; else if (IN_CLASSC(*netp)) *maskp = IN_CLASSC_NET; else { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "inet class for 0x%x unknown", *netp); return (-1); } } *netp &= *maskp; return (0); } #elif defined(_WIN32) /* * Return the name of a network interface attached to the system, or NULL * if none can be found. The interface must be configured up; the * lowest unit number is preferred; loopback is ignored. * * In the best of all possible worlds, this would be the same as on * UN*X, but there may be software that expects this to return a * full list of devices after the first device. */ #define ADAPTERSNAME_LEN 8192 char * pcap_lookupdev(errbuf) register char *errbuf; { DWORD dwVersion; DWORD dwWindowsMajorVersion; char our_errbuf[PCAP_ERRBUF_SIZE+1]; #pragma warning (push) #pragma warning (disable: 4996) /* disable MSVC's GetVersion() deprecated warning here */ dwVersion = GetVersion(); /* get the OS version */ #pragma warning (pop) dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) { /* * Windows 95, 98, ME. */ ULONG NameLength = ADAPTERSNAME_LEN; static char AdaptersName[ADAPTERSNAME_LEN]; if (PacketGetAdapterNames(AdaptersName,&NameLength) ) return (AdaptersName); else return NULL; } else { /* * Windows NT (NT 4.0 and later). * Convert the names to Unicode for backward compatibility. */ ULONG NameLength = ADAPTERSNAME_LEN; static WCHAR AdaptersName[ADAPTERSNAME_LEN]; size_t BufferSpaceLeft; char *tAstr; WCHAR *Unameptr; char *Adescptr; size_t namelen, i; WCHAR *TAdaptersName = (WCHAR*)malloc(ADAPTERSNAME_LEN * sizeof(WCHAR)); int NAdapts = 0; if(TAdaptersName == NULL) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure"); return NULL; } if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) ) { pcap_win32_err_to_str(GetLastError(), our_errbuf); (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "PacketGetAdapterNames: %s", our_errbuf); free(TAdaptersName); return NULL; } BufferSpaceLeft = ADAPTERSNAME_LEN * sizeof(WCHAR); tAstr = (char*)TAdaptersName; Unameptr = AdaptersName; /* * Convert the device names to Unicode into AdapterName. */ do { /* * Length of the name, including the terminating * NUL. */ namelen = strlen(tAstr) + 1; /* * Do we have room for the name in the Unicode * buffer? */ if (BufferSpaceLeft < namelen * sizeof(WCHAR)) { /* * No. */ goto quit; } BufferSpaceLeft -= namelen * sizeof(WCHAR); /* * Copy the name, converting ASCII to Unicode. * namelen includes the NUL, so we copy it as * well. */ for (i = 0; i < namelen; i++) *Unameptr++ = *tAstr++; /* * Count this adapter. */ NAdapts++; } while (namelen != 1); /* * Copy the descriptions, but don't convert them from * ASCII to Unicode. */ Adescptr = (char *)Unameptr; while(NAdapts--) { size_t desclen; desclen = strlen(tAstr) + 1; /* * Do we have room for the name in the Unicode * buffer? */ if (BufferSpaceLeft < desclen) { /* * No. */ goto quit; } /* * Just copy the ASCII string. * namelen includes the NUL, so we copy it as * well. */ memcpy(Adescptr, tAstr, desclen); Adescptr += desclen; tAstr += desclen; BufferSpaceLeft -= desclen; } quit: free(TAdaptersName); return (char *)(AdaptersName); } } int pcap_lookupnet(device, netp, maskp, errbuf) register const char *device; register bpf_u_int32 *netp, *maskp; register char *errbuf; { /* * We need only the first IPv4 address, so we must scan the array returned by PacketGetNetInfo() * in order to skip non IPv4 (i.e. IPv6 addresses) */ npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES]; LONG if_addr_size = 1; struct sockaddr_in *t_addr; unsigned int i; if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) { *netp = *maskp = 0; return (0); } for(i=0; isin_addr.S_un.S_addr; t_addr = (struct sockaddr_in *) &(if_addrs[i].SubnetMask); *maskp = t_addr->sin_addr.S_un.S_addr; *netp &= *maskp; return (0); } } *netp = *maskp = 0; return (0); } #endif /* !_WIN32 && !MSDOS */ libpcap-1.8.1/dlpisubs.c0000644000026300017510000002226113003771737013262 0ustar mcrmcr/* * This code is derived from code formerly in pcap-dlpi.c, originally * contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk), University College * London, and subsequently modified by Guy Harris (guy@alum.mit.edu), * Mark Pizzolato , * Mark C. Brown (mbrown@hp.com), and Sagun Shakya . */ /* * This file contains dlpi/libdlpi related common functions used * by pcap-[dlpi,libdlpi].c. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef DL_IPATM #define DL_IPATM 0x12 /* ATM Classical IP interface */ #endif #ifdef HAVE_SYS_BUFMOD_H /* * Size of a bufmod chunk to pass upstream; that appears to be the * biggest value to which you can set it, and setting it to that value * (which is bigger than what appears to be the Solaris default of 8192) * reduces the number of packet drops. */ #define CHUNKSIZE 65536 /* * Size of the buffer to allocate for packet data we read; it must be * large enough to hold a chunk. */ #define PKTBUFSIZE CHUNKSIZE #else /* HAVE_SYS_BUFMOD_H */ /* * Size of the buffer to allocate for packet data we read; this is * what the value used to be - there's no particular reason why it * should be tied to MAXDLBUF, but we'll leave it as this for now. */ #define MAXDLBUF 8192 #define PKTBUFSIZE (MAXDLBUF * sizeof(bpf_u_int32)) #endif #include #include #ifdef HAVE_SYS_BUFMOD_H #include #endif #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBDLPI #include #endif #include "pcap-int.h" #include "dlpisubs.h" #ifdef HAVE_SYS_BUFMOD_H static void pcap_stream_err(const char *, int, char *); #endif /* * Get the packet statistics. */ int pcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps) { struct pcap_dlpi *pd = p->priv; /* * "ps_recv" counts packets handed to the filter, not packets * that passed the filter. As filtering is done in userland, * this would not include packets dropped because we ran out * of buffer space; in order to make this more like other * platforms (Linux 2.4 and later, BSDs with BPF), where the * "packets received" count includes packets received but dropped * due to running out of buffer space, and to keep from confusing * applications that, for example, compute packet drop percentages, * we also make it count packets dropped by "bufmod" (otherwise we * might run the risk of the packet drop count being bigger than * the received-packet count). * * "ps_drop" counts packets dropped by "bufmod" because of * flow control requirements or resource exhaustion; it doesn't * count packets dropped by the interface driver, or packets * dropped upstream. As filtering is done in userland, it counts * packets regardless of whether they would've passed the filter. * * These statistics don't include packets not yet read from * the kernel by libpcap, but they may include packets not * yet read from libpcap by the application. */ *ps = pd->stat; /* * Add in the drop count, as per the above comment. */ ps->ps_recv += ps->ps_drop; return (0); } /* * Loop through the packets and call the callback for each packet. * Return the number of packets read. */ int pcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user, int count, u_char *bufp, int len) { struct pcap_dlpi *pd = p->priv; int n, caplen, origlen; u_char *ep, *pk; struct pcap_pkthdr pkthdr; #ifdef HAVE_SYS_BUFMOD_H struct sb_hdr *sbp; #ifdef LBL_ALIGN struct sb_hdr sbhdr; #endif #endif /* Loop through packets */ ep = bufp + len; n = 0; #ifdef HAVE_SYS_BUFMOD_H while (bufp < ep) { /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return -2 to indicate * that we were told to break out of the loop, otherwise * leave the flag set, so that the *next* call will break * out of the loop without having read any packets, and * return the number of packets we've processed so far. */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return (-2); } else { p->bp = bufp; p->cc = ep - bufp; return (n); } } #ifdef LBL_ALIGN if ((long)bufp & 3) { sbp = &sbhdr; memcpy(sbp, bufp, sizeof(*sbp)); } else #endif sbp = (struct sb_hdr *)bufp; pd->stat.ps_drop = sbp->sbh_drops; pk = bufp + sizeof(*sbp); bufp += sbp->sbh_totlen; origlen = sbp->sbh_origlen; caplen = sbp->sbh_msglen; #else origlen = len; caplen = min(p->snapshot, len); pk = bufp; bufp += caplen; #endif ++pd->stat.ps_recv; if (bpf_filter(p->fcode.bf_insns, pk, origlen, caplen)) { #ifdef HAVE_SYS_BUFMOD_H pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec; pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec; #else (void) gettimeofday(&pkthdr.ts, NULL); #endif pkthdr.len = origlen; pkthdr.caplen = caplen; /* Insure caplen does not exceed snapshot */ if (pkthdr.caplen > (bpf_u_int32)p->snapshot) pkthdr.caplen = (bpf_u_int32)p->snapshot; (*callback)(user, &pkthdr, pk); if (++n >= count && !PACKET_COUNT_IS_UNLIMITED(count)) { p->cc = ep - bufp; p->bp = bufp; return (n); } } #ifdef HAVE_SYS_BUFMOD_H } #endif p->cc = 0; return (n); } /* * Process the mac type. Returns -1 if no matching mac type found, otherwise 0. */ int pcap_process_mactype(pcap_t *p, u_int mactype) { int retv = 0; switch (mactype) { case DL_CSMACD: case DL_ETHER: p->linktype = DLT_EN10MB; p->offset = 2; /* * This is (presumably) a real Ethernet capture; give it a * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so * that an application can let you choose it, in case you're * capturing DOCSIS traffic that a Cisco Cable Modem * Termination System is putting out onto an Ethernet (it * doesn't put an Ethernet header onto the wire, it puts raw * DOCSIS frames out on the wire inside the low-level * Ethernet framing). */ p->dlt_list = (u_int *)malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (p->dlt_list != NULL) { p->dlt_list[0] = DLT_EN10MB; p->dlt_list[1] = DLT_DOCSIS; p->dlt_count = 2; } break; case DL_FDDI: p->linktype = DLT_FDDI; p->offset = 3; break; case DL_TPR: /* XXX - what about DL_TPB? Is that Token Bus? */ p->linktype = DLT_IEEE802; p->offset = 2; break; #ifdef HAVE_SOLARIS case DL_IPATM: p->linktype = DLT_SUNATM; p->offset = 0; /* works for LANE and LLC encapsulation */ break; #endif #ifdef DL_IPV4 case DL_IPV4: p->linktype = DLT_IPV4; p->offset = 0; break; #endif #ifdef DL_IPV6 case DL_IPV6: p->linktype = DLT_IPV6; p->offset = 0; break; #endif #ifdef DL_IPNET case DL_IPNET: p->linktype = DLT_IPNET; p->offset = 0; break; #endif default: pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype 0x%x", mactype); retv = -1; } return (retv); } #ifdef HAVE_SYS_BUFMOD_H /* * Push and configure the buffer module. Returns -1 for error, otherwise 0. */ int pcap_conf_bufmod(pcap_t *p, int snaplen) { struct timeval to; bpf_u_int32 ss, chunksize; /* Non-standard call to get the data nicely buffered. */ if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { pcap_stream_err("I_PUSH bufmod", errno, p->errbuf); return (-1); } ss = snaplen; if (ss > 0 && strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { pcap_stream_err("SBIOCSSNAP", errno, p->errbuf); return (-1); } if (p->opt.immediate) { /* Set the timeout to zero, for immediate delivery. */ to.tv_sec = 0; to.tv_usec = 0; if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { pcap_stream_err("SBIOCSTIME", errno, p->errbuf); return (-1); } } else { /* Set up the bufmod timeout. */ if (p->opt.timeout != 0) { to.tv_sec = p->opt.timeout / 1000; to.tv_usec = (p->opt.timeout * 1000) % 1000000; if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { pcap_stream_err("SBIOCSTIME", errno, p->errbuf); return (-1); } } /* Set the chunk length. */ chunksize = CHUNKSIZE; if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize) != 0) { pcap_stream_err("SBIOCSCHUNKP", errno, p->errbuf); return (-1); } } return (0); } #endif /* HAVE_SYS_BUFMOD_H */ /* * Allocate data buffer. Returns -1 if memory allocation fails, else 0. */ int pcap_alloc_databuf(pcap_t *p) { p->bufsize = PKTBUFSIZE; p->buffer = malloc(p->bufsize + p->offset); if (p->buffer == NULL) { strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); return (-1); } return (0); } /* * Issue a STREAMS I_STR ioctl. Returns -1 on error, otherwise * length of returned data on success. */ int strioctl(int fd, int cmd, int len, char *dp) { struct strioctl str; int retv; str.ic_cmd = cmd; str.ic_timout = -1; str.ic_len = len; str.ic_dp = dp; if ((retv = ioctl(fd, I_STR, &str)) < 0) return (retv); return (str.ic_len); } #ifdef HAVE_SYS_BUFMOD_H /* * Write stream error message to errbuf. */ static void pcap_stream_err(const char *func, int err, char *errbuf) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", func, pcap_strerror(err)); } #endif libpcap-1.8.1/pcap-null.c0000644000026300017510000000332513003771737013330 0ustar mcrmcr/* * Copyright (c) 1994, 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* optionally get BSD define */ #include #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #include "pcap-int.h" static char nosup[] = "live packet capture not supported on this system"; pcap_t * pcap_create_interface(const char *device _U_, char *ebuf) { (void)strlcpy(ebuf, nosup, PCAP_ERRBUF_SIZE); return (NULL); } int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { /* * There are no interfaces on which we can capture. */ *alldevsp = NULL; return (0); } libpcap-1.8.1/pcap_freecode.3pcap0000644000026300017510000000332313003771737014776 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_FREECODE 3PCAP "3 January 2014" .SH NAME pcap_freecode \- free a BPF program .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B void pcap_freecode(struct bpf_program *); .ft .fi .SH DESCRIPTION .B pcap_freecode() is used to free up allocated memory pointed to by a .I bpf_program struct generated by .B pcap_compile() when that BPF program is no longer needed, for example after it has been made the filter program for a pcap structure by a call to .BR pcap_setfilter() . .SH SEE ALSO pcap(3PCAP), pcap_compile(3PCAP), pcap_setfilter(3PCAP) libpcap-1.8.1/ieee80211.h0000644000026300017510000001247713003771737012755 0ustar mcrmcr/*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211.h,v 1.10 2005/07/22 16:55:27 sam Exp $ */ #ifndef _NET80211_IEEE80211_H_ #define _NET80211_IEEE80211_H_ /* * 802.11 protocol definitions. */ #define IEEE80211_FC0_VERSION_MASK 0x03 #define IEEE80211_FC0_VERSION_SHIFT 0 #define IEEE80211_FC0_VERSION_0 0x00 #define IEEE80211_FC0_TYPE_MASK 0x0c #define IEEE80211_FC0_TYPE_SHIFT 2 #define IEEE80211_FC0_TYPE_MGT 0x00 #define IEEE80211_FC0_TYPE_CTL 0x04 #define IEEE80211_FC0_TYPE_DATA 0x08 #define IEEE80211_FC0_SUBTYPE_MASK 0xf0 #define IEEE80211_FC0_SUBTYPE_SHIFT 4 /* for TYPE_MGT */ #define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00 #define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10 #define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20 #define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30 #define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40 #define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50 #define IEEE80211_FC0_SUBTYPE_BEACON 0x80 #define IEEE80211_FC0_SUBTYPE_ATIM 0x90 #define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0 #define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 #define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 /* for TYPE_CTL */ #define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0 #define IEEE80211_FC0_SUBTYPE_RTS 0xb0 #define IEEE80211_FC0_SUBTYPE_CTS 0xc0 #define IEEE80211_FC0_SUBTYPE_ACK 0xd0 #define IEEE80211_FC0_SUBTYPE_CF_END 0xe0 #define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0 /* for TYPE_DATA (bit combination) */ #define IEEE80211_FC0_SUBTYPE_DATA 0x00 #define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10 #define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20 #define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30 #define IEEE80211_FC0_SUBTYPE_NODATA 0x40 #define IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK 0x50 #define IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL 0x60 #define IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL 0x70 #define IEEE80211_FC0_SUBTYPE_QOS 0x80 #define IEEE80211_FC0_SUBTYPE_QOS_NULL 0xc0 #define IEEE80211_FC1_DIR_MASK 0x03 #define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ #define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ #define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ #define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ #define IEEE80211_FC1_MORE_FRAG 0x04 #define IEEE80211_FC1_RETRY 0x08 #define IEEE80211_FC1_PWR_MGT 0x10 #define IEEE80211_FC1_MORE_DATA 0x20 #define IEEE80211_FC1_WEP 0x40 #define IEEE80211_FC1_ORDER 0x80 #define IEEE80211_SEQ_FRAG_MASK 0x000f #define IEEE80211_SEQ_FRAG_SHIFT 0 #define IEEE80211_SEQ_SEQ_MASK 0xfff0 #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_NWID_LEN 32 #define IEEE80211_QOS_TXOP 0x00ff /* bit 8 is reserved */ #define IEEE80211_QOS_ACKPOLICY 0x60 #define IEEE80211_QOS_ACKPOLICY_S 5 #define IEEE80211_QOS_ESOP 0x10 #define IEEE80211_QOS_ESOP_S 4 #define IEEE80211_QOS_TID 0x0f #define IEEE80211_MGT_SUBTYPE_NAMES { \ "assoc-req", "assoc-resp", \ "reassoc-req", "reassoc-resp", \ "probe-req", "probe-resp", \ "reserved#6", "reserved#7", \ "beacon", "atim", \ "disassoc", "auth", \ "deauth", "reserved#13", \ "reserved#14", "reserved#15" \ } #define IEEE80211_CTL_SUBTYPE_NAMES { \ "reserved#0", "reserved#1", \ "reserved#2", "reserved#3", \ "reserved#3", "reserved#5", \ "reserved#6", "reserved#7", \ "reserved#8", "reserved#9", \ "ps-poll", "rts", \ "cts", "ack", \ "cf-end", "cf-end-ack" \ } #define IEEE80211_DATA_SUBTYPE_NAMES { \ "data", "data-cf-ack", \ "data-cf-poll", "data-cf-ack-poll", \ "null", "cf-ack", \ "cf-poll", "cf-ack-poll", \ "qos-data", "qos-data-cf-ack", \ "qos-data-cf-poll", "qos-data-cf-ack-poll", \ "qos", "reserved#13", \ "qos-cf-poll", "qos-cf-ack-poll" \ } #define IEEE80211_TYPE_NAMES { "mgt", "ctl", "data", "reserved#4" } #endif /* _NET80211_IEEE80211_H_ */ libpcap-1.8.1/pcap_setfilter.3pcap0000644000026300017510000000346213003771737015227 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_SETFILTER 3PCAP "7 April 2014" .SH NAME pcap_setfilter \- set the filter .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_setfilter(pcap_t *p, struct bpf_program *fp); .ft .fi .SH DESCRIPTION .B pcap_setfilter() is used to specify a filter program. .I fp is a pointer to a .I bpf_program struct, usually the result of a call to .BR pcap_compile() . .SH RETURN VALUE .B pcap_setfilter() returns 0 on success and \-1 on failure. If \-1 is returned, .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO pcap(3PCAP), pcap_compile(3PCAP), pcap_geterr(3PCAP) libpcap-1.8.1/pcap-usb-linux.c0000644000026300017510000006242613003771737014313 0ustar mcrmcr/* * Copyright (c) 2006 Paolo Abeni (Italy) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * USB sniffing API implementation for Linux platform * By Paolo Abeni * Modifications: Kris Katterjohn * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcap-int.h" #include "pcap-usb-linux.h" #include "pcap/usb.h" #ifdef NEED_STRERROR_H #include "strerror.h" #endif #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LINUX_USBDEVICE_FS_H /* * We might need to define __user for * . */ #ifdef HAVE_LINUX_COMPILER_H #include #endif /* HAVE_LINUX_COMPILER_H */ #include #endif /* HAVE_LINUX_USBDEVICE_FS_H */ #define USB_IFACE "usbmon" #define USB_TEXT_DIR_OLD "/sys/kernel/debug/usbmon" #define USB_TEXT_DIR "/sys/kernel/debug/usb/usbmon" #define SYS_USB_BUS_DIR "/sys/bus/usb/devices" #define PROC_USB_BUS_DIR "/proc/bus/usb" #define USB_LINE_LEN 4096 #if __BYTE_ORDER == __LITTLE_ENDIAN #define htols(s) s #define htoll(l) l #define htol64(ll) ll #else #define htols(s) bswap_16(s) #define htoll(l) bswap_32(l) #define htol64(ll) bswap_64(ll) #endif struct mon_bin_stats { u_int32_t queued; u_int32_t dropped; }; struct mon_bin_get { pcap_usb_header *hdr; void *data; size_t data_len; /* Length of data (can be zero) */ }; struct mon_bin_mfetch { int32_t *offvec; /* Vector of events fetched */ int32_t nfetch; /* Number of events to fetch (out: fetched) */ int32_t nflush; /* Number of events to flush */ }; #define MON_IOC_MAGIC 0x92 #define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1) #define MON_IOCX_URB _IOWR(MON_IOC_MAGIC, 2, struct mon_bin_hdr) #define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) #define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4) #define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5) #define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get) #define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch) #define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8) #define MON_BIN_SETUP 0x1 /* setup hdr is present*/ #define MON_BIN_SETUP_ZERO 0x2 /* setup buffer is not available */ #define MON_BIN_DATA_ZERO 0x4 /* data buffer is not available */ #define MON_BIN_ERROR 0x8 /* * Private data for capturing on Linux USB. */ struct pcap_usb_linux { u_char *mmapbuf; /* memory-mapped region pointer */ size_t mmapbuflen; /* size of region */ int bus_index; u_int packets_read; }; /* forward declaration */ static int usb_activate(pcap_t *); static int usb_stats_linux(pcap_t *, struct pcap_stat *); static int usb_stats_linux_bin(pcap_t *, struct pcap_stat *); static int usb_read_linux(pcap_t *, int , pcap_handler , u_char *); static int usb_read_linux_bin(pcap_t *, int , pcap_handler , u_char *); static int usb_read_linux_mmap(pcap_t *, int , pcap_handler , u_char *); static int usb_inject_linux(pcap_t *, const void *, size_t); static int usb_setdirection_linux(pcap_t *, pcap_direction_t); static void usb_cleanup_linux_mmap(pcap_t *); /* facility to add an USB device to the device list*/ static int usb_dev_add(pcap_if_t** alldevsp, int n, char *err_str) { char dev_name[10]; char dev_descr[30]; pcap_snprintf(dev_name, 10, USB_IFACE"%d", n); pcap_snprintf(dev_descr, 30, "USB bus number %d", n); if (pcap_add_if(alldevsp, dev_name, 0, dev_descr, err_str) < 0) return -1; return 0; } int usb_findalldevs(pcap_if_t **alldevsp, char *err_str) { int fd; struct dirent* data; int ret = 0; DIR* dir; int n; char* name; size_t len; /* * Do we have a "scan all buses" device? * First, try the binary device. */ fd = open(LINUX_USB_MON_DEV"0", O_RDONLY, 0); if (fd >= 0) { /* * Yes. */ close(fd); if (pcap_add_if(alldevsp, "usbmon0", 0, "All USB buses", err_str) < 0) return -1; } else { /* * No binary device; do we have the text device? */ fd = open(USB_TEXT_DIR"/0t", O_RDONLY, 0); if (fd < 0) { /* * Not at the new location; try the old location. */ fd = open(USB_TEXT_DIR_OLD"/0t", O_RDONLY, 0); } if (fd >= 0) { /* * We found it. */ close(fd); if (pcap_add_if(alldevsp, "usbmon0", 0, "All USB buses", err_str) < 0) return -1; } } /* * Now look for individual USB buses. * * First, try scanning sysfs USB bus directory. */ dir = opendir(SYS_USB_BUS_DIR); if (dir != NULL) { while ((ret == 0) && ((data = readdir(dir)) != 0)) { name = data->d_name; if (strncmp(name, "usb", 3) != 0) continue; if (sscanf(&name[3], "%d", &n) == 0) continue; ret = usb_dev_add(alldevsp, n, err_str); } closedir(dir); return ret; } /* That didn't work; try scanning procfs USB bus directory. */ dir = opendir(PROC_USB_BUS_DIR); if (dir != NULL) { while ((ret == 0) && ((data = readdir(dir)) != 0)) { name = data->d_name; len = strlen(name); /* if this file name does not end with a number it's not of our interest */ if ((len < 1) || !isdigit(name[--len])) continue; while (isdigit(name[--len])); if (sscanf(&name[len+1], "%d", &n) != 1) continue; ret = usb_dev_add(alldevsp, n, err_str); } closedir(dir); return ret; } /* neither of them worked */ return 0; } static int usb_mmap(pcap_t* handle) { struct pcap_usb_linux *handlep = handle->priv; int len = ioctl(handle->fd, MON_IOCQ_RING_SIZE); if (len < 0) return 0; handlep->mmapbuflen = len; handlep->mmapbuf = mmap(0, handlep->mmapbuflen, PROT_READ, MAP_SHARED, handle->fd, 0); return handlep->mmapbuf != MAP_FAILED; } #ifdef HAVE_LINUX_USBDEVICE_FS_H #define CTRL_TIMEOUT (5*1000) /* milliseconds */ #define USB_DIR_IN 0x80 #define USB_TYPE_STANDARD 0x00 #define USB_RECIP_DEVICE 0x00 #define USB_REQ_GET_DESCRIPTOR 6 #define USB_DT_DEVICE 1 /* probe the descriptors of the devices attached to the bus */ /* the descriptors will end up in the captured packet stream */ /* and be decoded by external apps like wireshark */ /* without these identifying probes packet data can't be fully decoded */ static void probe_devices(int bus) { struct usbdevfs_ctrltransfer ctrl; struct dirent* data; int ret = 0; char buf[40]; DIR* dir; /* scan usb bus directories for device nodes */ pcap_snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d", bus); dir = opendir(buf); if (!dir) return; while ((ret >= 0) && ((data = readdir(dir)) != 0)) { int fd; char* name = data->d_name; if (name[0] == '.') continue; pcap_snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d/%s", bus, data->d_name); fd = open(buf, O_RDWR); if (fd == -1) continue; /* * Sigh. Different kernels have different member names * for this structure. */ #ifdef HAVE_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE ctrl.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; ctrl.wValue = USB_DT_DEVICE << 8; ctrl.wIndex = 0; ctrl.wLength = sizeof(buf); #else ctrl.requesttype = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; ctrl.request = USB_REQ_GET_DESCRIPTOR; ctrl.value = USB_DT_DEVICE << 8; ctrl.index = 0; ctrl.length = sizeof(buf); #endif ctrl.data = buf; ctrl.timeout = CTRL_TIMEOUT; ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl); close(fd); } closedir(dir); } #endif /* HAVE_LINUX_USBDEVICE_FS_H */ pcap_t * usb_create(const char *device, char *ebuf, int *is_ours) { const char *cp; char *cpend; long devnum; pcap_t *p; /* Does this look like a USB monitoring device? */ cp = strrchr(device, '/'); if (cp == NULL) cp = device; /* Does it begin with USB_IFACE? */ if (strncmp(cp, USB_IFACE, sizeof USB_IFACE - 1) != 0) { /* Nope, doesn't begin with USB_IFACE */ *is_ours = 0; return NULL; } /* Yes - is USB_IFACE followed by a number? */ cp += sizeof USB_IFACE - 1; devnum = strtol(cp, &cpend, 10); if (cpend == cp || *cpend != '\0') { /* Not followed by a number. */ *is_ours = 0; return NULL; } if (devnum < 0) { /* Followed by a non-valid number. */ *is_ours = 0; return NULL; } /* OK, it's probably ours. */ *is_ours = 1; p = pcap_create_common(ebuf, sizeof (struct pcap_usb_linux)); if (p == NULL) return (NULL); p->activate_op = usb_activate; return (p); } static int usb_activate(pcap_t* handle) { struct pcap_usb_linux *handlep = handle->priv; char full_path[USB_LINE_LEN]; /* Initialize some components of the pcap structure. */ handle->bufsize = handle->snapshot; handle->offset = 0; handle->linktype = DLT_USB_LINUX; handle->inject_op = usb_inject_linux; handle->setfilter_op = install_bpf_program; /* no kernel filtering */ handle->setdirection_op = usb_setdirection_linux; handle->set_datalink_op = NULL; /* can't change data link type */ handle->getnonblock_op = pcap_getnonblock_fd; handle->setnonblock_op = pcap_setnonblock_fd; /*get usb bus index from device name */ if (sscanf(handle->opt.device, USB_IFACE"%d", &handlep->bus_index) != 1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get USB bus index from %s", handle->opt.device); return PCAP_ERROR; } /*now select the read method: try to open binary interface */ pcap_snprintf(full_path, USB_LINE_LEN, LINUX_USB_MON_DEV"%d", handlep->bus_index); handle->fd = open(full_path, O_RDONLY, 0); if (handle->fd >= 0) { if (handle->opt.rfmon) { /* * Monitor mode doesn't apply to USB devices. */ close(handle->fd); return PCAP_ERROR_RFMON_NOTSUP; } /* binary api is available, try to use fast mmap access */ if (usb_mmap(handle)) { handle->linktype = DLT_USB_LINUX_MMAPPED; handle->stats_op = usb_stats_linux_bin; handle->read_op = usb_read_linux_mmap; handle->cleanup_op = usb_cleanup_linux_mmap; #ifdef HAVE_LINUX_USBDEVICE_FS_H probe_devices(handlep->bus_index); #endif /* * "handle->fd" is a real file, so "select()" and * "poll()" work on it. */ handle->selectable_fd = handle->fd; return 0; } /* can't mmap, use plain binary interface access */ handle->stats_op = usb_stats_linux_bin; handle->read_op = usb_read_linux_bin; #ifdef HAVE_LINUX_USBDEVICE_FS_H probe_devices(handlep->bus_index); #endif } else { /*Binary interface not available, try open text interface */ pcap_snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR"/%dt", handlep->bus_index); handle->fd = open(full_path, O_RDONLY, 0); if (handle->fd < 0) { if (errno == ENOENT) { /* * Not found at the new location; try * the old location. */ pcap_snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%dt", handlep->bus_index); handle->fd = open(full_path, O_RDONLY, 0); } if (handle->fd < 0) { /* no more fallback, give it up*/ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't open USB bus file %s: %s", full_path, strerror(errno)); return PCAP_ERROR; } } if (handle->opt.rfmon) { /* * Monitor mode doesn't apply to USB devices. */ close(handle->fd); return PCAP_ERROR_RFMON_NOTSUP; } handle->stats_op = usb_stats_linux; handle->read_op = usb_read_linux; } /* * "handle->fd" is a real file, so "select()" and "poll()" * work on it. */ handle->selectable_fd = handle->fd; /* for plain binary access and text access we need to allocate the read * buffer */ handle->buffer = malloc(handle->bufsize); if (!handle->buffer) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); close(handle->fd); return PCAP_ERROR; } return 0; } static inline int ascii_to_int(char c) { return c < 'A' ? c- '0': ((c<'a') ? c - 'A' + 10: c-'a'+10); } /* * see /Documentation/usb/usbmon.txt and * /drivers/usb/mon/mon_text.c for urb string * format description */ static int usb_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { /* see: * /usr/src/linux/Documentation/usb/usbmon.txt * for message format */ struct pcap_usb_linux *handlep = handle->priv; unsigned timestamp; int tag, cnt, ep_num, dev_addr, dummy, ret, urb_len, data_len; char etype, pipeid1, pipeid2, status[16], urb_tag, line[USB_LINE_LEN]; char *string = line; u_char * rawdata = handle->buffer; struct pcap_pkthdr pkth; pcap_usb_header* uhdr = (pcap_usb_header*)handle->buffer; u_char urb_transfer=0; int incoming=0; /* ignore interrupt system call errors */ do { ret = read(handle->fd, line, USB_LINE_LEN - 1); if (handle->break_loop) { handle->break_loop = 0; return -2; } } while ((ret == -1) && (errno == EINTR)); if (ret < 0) { if (errno == EAGAIN) return 0; /* no data there */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't read from fd %d: %s", handle->fd, strerror(errno)); return -1; } /* read urb header; %n argument may increment return value, but it's * not mandatory, so does not count on it*/ string[ret] = 0; ret = sscanf(string, "%x %d %c %c%c:%d:%d %s%n", &tag, ×tamp, &etype, &pipeid1, &pipeid2, &dev_addr, &ep_num, status, &cnt); if (ret < 8) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't parse USB bus message '%s', too few tokens (expected 8 got %d)", string, ret); return -1; } uhdr->id = tag; uhdr->device_address = dev_addr; uhdr->bus_id = handlep->bus_index; uhdr->status = 0; string += cnt; /* don't use usbmon provided timestamp, since it have low precision*/ if (gettimeofday(&pkth.ts, NULL) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get timestamp for message '%s' %d:%s", string, errno, strerror(errno)); return -1; } uhdr->ts_sec = pkth.ts.tv_sec; uhdr->ts_usec = pkth.ts.tv_usec; /* parse endpoint information */ if (pipeid1 == 'C') urb_transfer = URB_CONTROL; else if (pipeid1 == 'Z') urb_transfer = URB_ISOCHRONOUS; else if (pipeid1 == 'I') urb_transfer = URB_INTERRUPT; else if (pipeid1 == 'B') urb_transfer = URB_BULK; if (pipeid2 == 'i') { ep_num |= URB_TRANSFER_IN; incoming = 1; } if (etype == 'C') incoming = !incoming; /* direction check*/ if (incoming) { if (handle->direction == PCAP_D_OUT) return 0; } else if (handle->direction == PCAP_D_IN) return 0; uhdr->event_type = etype; uhdr->transfer_type = urb_transfer; uhdr->endpoint_number = ep_num; pkth.caplen = sizeof(pcap_usb_header); rawdata += sizeof(pcap_usb_header); /* check if this is a setup packet */ ret = sscanf(status, "%d", &dummy); if (ret != 1) { /* this a setup packet, setup data can be filled with underscore if * usbmon has not been able to read them, so we must parse this fields as * strings */ pcap_usb_setup* shdr; char str1[3], str2[3], str3[5], str4[5], str5[5]; ret = sscanf(string, "%s %s %s %s %s%n", str1, str2, str3, str4, str5, &cnt); if (ret < 5) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't parse USB bus message '%s', too few tokens (expected 5 got %d)", string, ret); return -1; } string += cnt; /* try to convert to corresponding integer */ shdr = &uhdr->setup; shdr->bmRequestType = strtoul(str1, 0, 16); shdr->bRequest = strtoul(str2, 0, 16); shdr->wValue = htols(strtoul(str3, 0, 16)); shdr->wIndex = htols(strtoul(str4, 0, 16)); shdr->wLength = htols(strtoul(str5, 0, 16)); uhdr->setup_flag = 0; } else uhdr->setup_flag = 1; /* read urb data */ ret = sscanf(string, " %d%n", &urb_len, &cnt); if (ret < 1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't parse urb length from '%s'", string); return -1; } string += cnt; /* urb tag is not present if urb length is 0, so we can stop here * text parsing */ pkth.len = urb_len+pkth.caplen; uhdr->urb_len = urb_len; uhdr->data_flag = 1; data_len = 0; if (uhdr->urb_len == 0) goto got; /* check for data presence; data is present if and only if urb tag is '=' */ if (sscanf(string, " %c", &urb_tag) != 1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't parse urb tag from '%s'", string); return -1; } if (urb_tag != '=') goto got; /* skip urb tag and following space */ string += 3; /* if we reach this point we got some urb data*/ uhdr->data_flag = 0; /* read all urb data; if urb length is greater then the usbmon internal * buffer length used by the kernel to spool the URB, we get only * a partial information. * At least until linux 2.6.17 there is no way to set usbmon intenal buffer * length and default value is 130. */ while ((string[0] != 0) && (string[1] != 0) && (pkth.caplen < (bpf_u_int32)handle->snapshot)) { rawdata[0] = ascii_to_int(string[0]) * 16 + ascii_to_int(string[1]); rawdata++; string+=2; if (string[0] == ' ') string++; pkth.caplen++; data_len++; } got: uhdr->data_len = data_len; if (pkth.caplen > (bpf_u_int32)handle->snapshot) pkth.caplen = (bpf_u_int32)handle->snapshot; if (handle->fcode.bf_insns == NULL || bpf_filter(handle->fcode.bf_insns, handle->buffer, pkth.len, pkth.caplen)) { handlep->packets_read++; callback(user, &pkth, handle->buffer); return 1; } return 0; /* didn't pass filter */ } static int usb_inject_linux(pcap_t *handle, const void *buf, size_t size) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on " "USB devices"); return (-1); } static int usb_stats_linux(pcap_t *handle, struct pcap_stat *stats) { struct pcap_usb_linux *handlep = handle->priv; int dummy, ret, consumed, cnt; char string[USB_LINE_LEN]; char token[USB_LINE_LEN]; char * ptr = string; int fd; pcap_snprintf(string, USB_LINE_LEN, USB_TEXT_DIR"/%ds", handlep->bus_index); fd = open(string, O_RDONLY, 0); if (fd < 0) { if (errno == ENOENT) { /* * Not found at the new location; try the old * location. */ pcap_snprintf(string, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%ds", handlep->bus_index); fd = open(string, O_RDONLY, 0); } if (fd < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't open USB stats file %s: %s", string, strerror(errno)); return -1; } } /* read stats line */ do { ret = read(fd, string, USB_LINE_LEN-1); } while ((ret == -1) && (errno == EINTR)); close(fd); if (ret < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't read stats from fd %d ", fd); return -1; } string[ret] = 0; /* extract info on dropped urbs */ for (consumed=0; consumed < ret; ) { /* from the sscanf man page: * The C standard says: "Execution of a %n directive does * not increment the assignment count returned at the completion * of execution" but the Corrigendum seems to contradict this. * Do not make any assumptions on the effect of %n conversions * on the return value and explicitly check for cnt assignmet*/ int ntok; cnt = -1; ntok = sscanf(ptr, "%s%n", token, &cnt); if ((ntok < 1) || (cnt < 0)) break; consumed += cnt; ptr += cnt; if (strcmp(token, "nreaders") == 0) ret = sscanf(ptr, "%d", &stats->ps_drop); else ret = sscanf(ptr, "%d", &dummy); if (ntok != 1) break; consumed += cnt; ptr += cnt; } stats->ps_recv = handlep->packets_read; stats->ps_ifdrop = 0; return 0; } static int usb_setdirection_linux(pcap_t *p, pcap_direction_t d) { p->direction = d; return 0; } static int usb_stats_linux_bin(pcap_t *handle, struct pcap_stat *stats) { struct pcap_usb_linux *handlep = handle->priv; int ret; struct mon_bin_stats st; ret = ioctl(handle->fd, MON_IOCG_STATS, &st); if (ret < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't read stats from fd %d:%s ", handle->fd, strerror(errno)); return -1; } stats->ps_recv = handlep->packets_read + st.queued; stats->ps_drop = st.dropped; stats->ps_ifdrop = 0; return 0; } /* * see /Documentation/usb/usbmon.txt and * /drivers/usb/mon/mon_bin.c binary ABI */ static int usb_read_linux_bin(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_usb_linux *handlep = handle->priv; struct mon_bin_get info; int ret; struct pcap_pkthdr pkth; u_int clen = handle->snapshot - sizeof(pcap_usb_header); /* the usb header is going to be part of 'packet' data*/ info.hdr = (pcap_usb_header*) handle->buffer; info.data = (u_char *)handle->buffer + sizeof(pcap_usb_header); info.data_len = clen; /* ignore interrupt system call errors */ do { ret = ioctl(handle->fd, MON_IOCX_GET, &info); if (handle->break_loop) { handle->break_loop = 0; return -2; } } while ((ret == -1) && (errno == EINTR)); if (ret < 0) { if (errno == EAGAIN) return 0; /* no data there */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't read from fd %d: %s", handle->fd, strerror(errno)); return -1; } /* we can get less that than really captured from kernel, depending on * snaplen, so adjust header accordingly */ if (info.hdr->data_len < clen) clen = info.hdr->data_len; info.hdr->data_len = clen; pkth.caplen = clen + sizeof(pcap_usb_header); pkth.len = info.hdr->data_len + sizeof(pcap_usb_header); pkth.ts.tv_sec = info.hdr->ts_sec; pkth.ts.tv_usec = info.hdr->ts_usec; if (handle->fcode.bf_insns == NULL || bpf_filter(handle->fcode.bf_insns, handle->buffer, pkth.len, pkth.caplen)) { handlep->packets_read++; callback(user, &pkth, handle->buffer); return 1; } return 0; /* didn't pass filter */ } /* * see /Documentation/usb/usbmon.txt and * /drivers/usb/mon/mon_bin.c binary ABI */ #define VEC_SIZE 32 static int usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_usb_linux *handlep = handle->priv; struct mon_bin_mfetch fetch; int32_t vec[VEC_SIZE]; struct pcap_pkthdr pkth; pcap_usb_header* hdr; int nflush = 0; int packets = 0; u_int clen, max_clen; max_clen = handle->snapshot - sizeof(pcap_usb_header); for (;;) { int i, ret; int limit = max_packets - packets; if (limit <= 0) limit = VEC_SIZE; if (limit > VEC_SIZE) limit = VEC_SIZE; /* try to fetch as many events as possible*/ fetch.offvec = vec; fetch.nfetch = limit; fetch.nflush = nflush; /* ignore interrupt system call errors */ do { ret = ioctl(handle->fd, MON_IOCX_MFETCH, &fetch); if (handle->break_loop) { handle->break_loop = 0; return -2; } } while ((ret == -1) && (errno == EINTR)); if (ret < 0) { if (errno == EAGAIN) return 0; /* no data there */ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't mfetch fd %d: %s", handle->fd, strerror(errno)); return -1; } /* keep track of processed events, we will flush them later */ nflush = fetch.nfetch; for (i=0; immapbuf[vec[i]]; if (hdr->event_type == '@') continue; /* we can get less that than really captured from kernel, depending on * snaplen, so adjust header accordingly */ clen = max_clen; if (hdr->data_len < clen) clen = hdr->data_len; /* get packet info from header*/ pkth.caplen = clen + sizeof(pcap_usb_header_mmapped); pkth.len = hdr->data_len + sizeof(pcap_usb_header_mmapped); pkth.ts.tv_sec = hdr->ts_sec; pkth.ts.tv_usec = hdr->ts_usec; if (handle->fcode.bf_insns == NULL || bpf_filter(handle->fcode.bf_insns, (u_char*) hdr, pkth.len, pkth.caplen)) { handlep->packets_read++; callback(user, &pkth, (u_char*) hdr); packets++; } } /* with max_packets specifying "unlimited" we stop afer the first chunk*/ if (PACKET_COUNT_IS_UNLIMITED(max_packets) || (packets == max_packets)) break; } /* flush pending events*/ if (ioctl(handle->fd, MON_IOCH_MFLUSH, nflush) == -1) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't mflush fd %d: %s", handle->fd, strerror(errno)); return -1; } return packets; } static void usb_cleanup_linux_mmap(pcap_t* handle) { struct pcap_usb_linux *handlep = handle->priv; /* if we have a memory-mapped buffer, unmap it */ if (handlep->mmapbuf != NULL) { munmap(handlep->mmapbuf, handlep->mmapbuflen); handlep->mmapbuf = NULL; } pcap_cleanup_live_common(handle); } libpcap-1.8.1/config.guess0000644000026300017510000012452613003771737013615 0ustar mcrmcr#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2015 Free Software Foundation, Inc. timestamp='2015-02-23' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || \ echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case "${UNAME_MACHINE_ARCH}" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: libpcap-1.8.1/LICENSE0000644000026300017510000000154413003771737012277 0ustar mcrmcrLicense: BSD Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not 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. libpcap-1.8.1/pcap-dag.c0000644000026300017510000010627713003771737013123 0ustar mcrmcr/* * pcap-dag.c: Packet capture interface for Emulex EndaceDAG cards. * * The functionality of this code attempts to mimic that of pcap-linux as much * as possible. This code is compiled in several different ways depending on * whether DAG_ONLY and HAVE_DAG_API are defined. If HAVE_DAG_API is not * defined it should not get compiled in, otherwise if DAG_ONLY is defined then * the 'dag_' function calls are renamed to 'pcap_' equivalents. If DAG_ONLY * is not defined then nothing is altered - the dag_ functions will be * called as required from their pcap-linux/bpf equivalents. * * Authors: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com) * Modifications: Jesper Peterson * Koryn Grant * Stephen Donnelly */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* optionally get BSD define */ #include #include #include #include "pcap-int.h" #include #include #include #include #include #include struct mbuf; /* Squelch compiler warnings on some platforms for */ struct rtentry; /* declarations in */ #include #include "dagnew.h" #include "dagapi.h" #include "dagpci.h" #include "pcap-dag.h" /* * DAG devices have names beginning with "dag", followed by a number * from 0 to DAG_MAX_BOARDS, then optionally a colon and a stream number * from 0 to DAG_STREAM_MAX. */ #ifndef DAG_MAX_BOARDS #define DAG_MAX_BOARDS 32 #endif #ifndef TYPE_AAL5 #define TYPE_AAL5 4 #endif #ifndef TYPE_MC_HDLC #define TYPE_MC_HDLC 5 #endif #ifndef TYPE_MC_RAW #define TYPE_MC_RAW 6 #endif #ifndef TYPE_MC_ATM #define TYPE_MC_ATM 7 #endif #ifndef TYPE_MC_RAW_CHANNEL #define TYPE_MC_RAW_CHANNEL 8 #endif #ifndef TYPE_MC_AAL5 #define TYPE_MC_AAL5 9 #endif #ifndef TYPE_COLOR_HDLC_POS #define TYPE_COLOR_HDLC_POS 10 #endif #ifndef TYPE_COLOR_ETH #define TYPE_COLOR_ETH 11 #endif #ifndef TYPE_MC_AAL2 #define TYPE_MC_AAL2 12 #endif #ifndef TYPE_IP_COUNTER #define TYPE_IP_COUNTER 13 #endif #ifndef TYPE_TCP_FLOW_COUNTER #define TYPE_TCP_FLOW_COUNTER 14 #endif #ifndef TYPE_DSM_COLOR_HDLC_POS #define TYPE_DSM_COLOR_HDLC_POS 15 #endif #ifndef TYPE_DSM_COLOR_ETH #define TYPE_DSM_COLOR_ETH 16 #endif #ifndef TYPE_COLOR_MC_HDLC_POS #define TYPE_COLOR_MC_HDLC_POS 17 #endif #ifndef TYPE_AAL2 #define TYPE_AAL2 18 #endif #ifndef TYPE_COLOR_HASH_POS #define TYPE_COLOR_HASH_POS 19 #endif #ifndef TYPE_COLOR_HASH_ETH #define TYPE_COLOR_HASH_ETH 20 #endif #ifndef TYPE_INFINIBAND #define TYPE_INFINIBAND 21 #endif #ifndef TYPE_IPV4 #define TYPE_IPV4 22 #endif #ifndef TYPE_IPV6 #define TYPE_IPV6 23 #endif #ifndef TYPE_RAW_LINK #define TYPE_RAW_LINK 24 #endif #ifndef TYPE_INFINIBAND_LINK #define TYPE_INFINIBAND_LINK 25 #endif #ifndef TYPE_PAD #define TYPE_PAD 48 #endif #define ATM_CELL_SIZE 52 #define ATM_HDR_SIZE 4 /* * A header containing additional MTP information. */ #define MTP2_SENT_OFFSET 0 /* 1 byte */ #define MTP2_ANNEX_A_USED_OFFSET 1 /* 1 byte */ #define MTP2_LINK_NUMBER_OFFSET 2 /* 2 bytes */ #define MTP2_HDR_LEN 4 /* length of the header */ #define MTP2_ANNEX_A_NOT_USED 0 #define MTP2_ANNEX_A_USED 1 #define MTP2_ANNEX_A_USED_UNKNOWN 2 /* SunATM pseudo header */ struct sunatm_hdr { unsigned char flags; /* destination and traffic type */ unsigned char vpi; /* VPI */ unsigned short vci; /* VCI */ }; /* * Private data for capturing on DAG devices. */ struct pcap_dag { struct pcap_stat stat; #ifdef HAVE_DAG_STREAMS_API u_char *dag_mem_bottom; /* DAG card current memory bottom pointer */ u_char *dag_mem_top; /* DAG card current memory top pointer */ #else /* HAVE_DAG_STREAMS_API */ void *dag_mem_base; /* DAG card memory base address */ u_int dag_mem_bottom; /* DAG card current memory bottom offset */ u_int dag_mem_top; /* DAG card current memory top offset */ #endif /* HAVE_DAG_STREAMS_API */ int dag_fcs_bits; /* Number of checksum bits from link layer */ int dag_offset_flags; /* Flags to pass to dag_offset(). */ int dag_stream; /* DAG stream number */ int dag_timeout; /* timeout specified to pcap_open_live. * Same as in linux above, introduce * generally? */ }; typedef struct pcap_dag_node { struct pcap_dag_node *next; pcap_t *p; pid_t pid; } pcap_dag_node_t; static pcap_dag_node_t *pcap_dags = NULL; static int atexit_handler_installed = 0; static const unsigned short endian_test_word = 0x0100; #define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word)) #define MAX_DAG_PACKET 65536 static unsigned char TempPkt[MAX_DAG_PACKET]; static int dag_setfilter(pcap_t *p, struct bpf_program *fp); static int dag_stats(pcap_t *p, struct pcap_stat *ps); static int dag_set_datalink(pcap_t *p, int dlt); static int dag_get_datalink(pcap_t *p); static int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf); static void delete_pcap_dag(pcap_t *p) { pcap_dag_node_t *curr = NULL, *prev = NULL; for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) { /* empty */ } if (curr != NULL && curr->p == p) { if (prev != NULL) { prev->next = curr->next; } else { pcap_dags = curr->next; } } } /* * Performs a graceful shutdown of the DAG card, frees dynamic memory held * in the pcap_t structure, and closes the file descriptor for the DAG card. */ static void dag_platform_cleanup(pcap_t *p) { struct pcap_dag *pd = p->pr; #ifdef HAVE_DAG_STREAMS_API if(dag_stop_stream(p->fd, pd->dag_stream) < 0) fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); if(dag_detach_stream(p->fd, pd->dag_stream) < 0) fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); #else if(dag_stop(p->fd) < 0) fprintf(stderr,"dag_stop: %s\n", strerror(errno)); #endif /* HAVE_DAG_STREAMS_API */ if(p->fd != -1) { if(dag_close(p->fd) < 0) fprintf(stderr,"dag_close: %s\n", strerror(errno)); p->fd = -1; } delete_pcap_dag(p); pcap_cleanup_live_common(p); /* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */ } static void atexit_handler(void) { while (pcap_dags != NULL) { if (pcap_dags->pid == getpid()) { if (pcap_dags->p != NULL) dag_platform_cleanup(pcap_dags->p); } else { delete_pcap_dag(pcap_dags->p); } } } static int new_pcap_dag(pcap_t *p) { pcap_dag_node_t *node = NULL; if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) { return -1; } if (!atexit_handler_installed) { atexit(atexit_handler); atexit_handler_installed = 1; } node->next = pcap_dags; node->p = p; node->pid = getpid(); pcap_dags = node; return 0; } static unsigned int dag_erf_ext_header_count(uint8_t * erf, size_t len) { uint32_t hdr_num = 0; uint8_t hdr_type; /* basic sanity checks */ if ( erf == NULL ) return 0; if ( len < 16 ) return 0; /* check if we have any extension headers */ if ( (erf[8] & 0x80) == 0x00 ) return 0; /* loop over the extension headers */ do { /* sanity check we have enough bytes */ if ( len < (24 + (hdr_num * 8)) ) return hdr_num; /* get the header type */ hdr_type = erf[(16 + (hdr_num * 8))]; hdr_num++; } while ( hdr_type & 0x80 ); return hdr_num; } /* * Read at most max_packets from the capture stream and call the callback * for each of them. Returns the number of packets handled, -1 if an * error occured, or -2 if we were told to break out of the loop. */ static int dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct pcap_dag *pd = p->priv; unsigned int processed = 0; int flags = pd->dag_offset_flags; unsigned int nonblocking = flags & DAGF_NONBLOCK; unsigned int num_ext_hdr = 0; unsigned int ticks_per_second; /* Get the next bufferful of packets (if necessary). */ while (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size) { /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that * it has, and return -2 to indicate that * we were told to break out of the loop. */ p->break_loop = 0; return -2; } #ifdef HAVE_DAG_STREAMS_API /* dag_advance_stream() will block (unless nonblock is called) * until 64kB of data has accumulated. * If to_ms is set, it will timeout before 64kB has accumulated. * We wait for 64kB because processing a few packets at a time * can cause problems at high packet rates (>200kpps) due * to inefficiencies. * This does mean if to_ms is not specified the capture may 'hang' * for long periods if the data rate is extremely slow (<64kB/sec) * If non-block is specified it will return immediately. The user * is then responsible for efficiency. */ if ( NULL == (pd->dag_mem_top = dag_advance_stream(p->fd, pd->dag_stream, &(pd->dag_mem_bottom))) ) { return -1; } #else /* dag_offset does not support timeouts */ pd->dag_mem_top = dag_offset(p->fd, &(pd->dag_mem_bottom), flags); #endif /* HAVE_DAG_STREAMS_API */ if (nonblocking && (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size)) { /* Pcap is configured to process only available packets, and there aren't any, return immediately. */ return 0; } if(!nonblocking && pd->dag_timeout && (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size)) { /* Blocking mode, but timeout set and no data has arrived, return anyway.*/ return 0; } } /* Process the packets. */ while (pd->dag_mem_top - pd->dag_mem_bottom >= dag_record_size) { unsigned short packet_len = 0; int caplen = 0; struct pcap_pkthdr pcap_header; #ifdef HAVE_DAG_STREAMS_API dag_record_t *header = (dag_record_t *)(pd->dag_mem_bottom); #else dag_record_t *header = (dag_record_t *)(pd->dag_mem_base + pd->dag_mem_bottom); #endif /* HAVE_DAG_STREAMS_API */ u_char *dp = ((u_char *)header); /* + dag_record_size; */ unsigned short rlen; /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that * it has, and return -2 to indicate that * we were told to break out of the loop. */ p->break_loop = 0; return -2; } rlen = ntohs(header->rlen); if (rlen < dag_record_size) { strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE); return -1; } pd->dag_mem_bottom += rlen; /* Count lost packets. */ switch((header->type & 0x7f)) { /* in these types the color value overwrites the lctr */ case TYPE_COLOR_HDLC_POS: case TYPE_COLOR_ETH: case TYPE_DSM_COLOR_HDLC_POS: case TYPE_DSM_COLOR_ETH: case TYPE_COLOR_MC_HDLC_POS: case TYPE_COLOR_HASH_ETH: case TYPE_COLOR_HASH_POS: break; default: if (header->lctr) { if (pd->stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) { pd->stat.ps_drop = UINT_MAX; } else { pd->stat.ps_drop += ntohs(header->lctr); } } } if ((header->type & 0x7f) == TYPE_PAD) { continue; } num_ext_hdr = dag_erf_ext_header_count(dp, rlen); /* ERF encapsulation */ /* The Extensible Record Format is not dropped for this kind of encapsulation, * and will be handled as a pseudo header by the decoding application. * The information carried in the ERF header and in the optional subheader (if present) * could be merged with the libpcap information, to offer a better decoding. * The packet length is * o the length of the packet on the link (header->wlen), * o plus the length of the ERF header (dag_record_size), as the length of the * pseudo header will be adjusted during the decoding, * o plus the length of the optional subheader (if present). * * The capture length is header.rlen and the byte stuffing for alignment will be dropped * if the capture length is greater than the packet length. */ if (p->linktype == DLT_ERF) { packet_len = ntohs(header->wlen) + dag_record_size; caplen = rlen; switch ((header->type & 0x7f)) { case TYPE_MC_AAL5: case TYPE_MC_ATM: case TYPE_MC_HDLC: case TYPE_MC_RAW_CHANNEL: case TYPE_MC_RAW: case TYPE_MC_AAL2: case TYPE_COLOR_MC_HDLC_POS: packet_len += 4; /* MC header */ break; case TYPE_COLOR_HASH_ETH: case TYPE_DSM_COLOR_ETH: case TYPE_COLOR_ETH: case TYPE_ETH: packet_len += 2; /* ETH header */ break; } /* switch type */ /* Include ERF extension headers */ packet_len += (8 * num_ext_hdr); if (caplen > packet_len) { caplen = packet_len; } } else { /* Other kind of encapsulation according to the header Type */ /* Skip over generic ERF header */ dp += dag_record_size; /* Skip over extension headers */ dp += 8 * num_ext_hdr; switch((header->type & 0x7f)) { case TYPE_ATM: case TYPE_AAL5: if (header->type == TYPE_AAL5) { packet_len = ntohs(header->wlen); caplen = rlen - dag_record_size; } case TYPE_MC_ATM: if (header->type == TYPE_MC_ATM) { caplen = packet_len = ATM_CELL_SIZE; dp+=4; } case TYPE_MC_AAL5: if (header->type == TYPE_MC_AAL5) { packet_len = ntohs(header->wlen); caplen = rlen - dag_record_size - 4; dp+=4; } /* Skip over extension headers */ caplen -= (8 * num_ext_hdr); if (header->type == TYPE_ATM) { caplen = packet_len = ATM_CELL_SIZE; } if (p->linktype == DLT_SUNATM) { struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp; unsigned long rawatm; rawatm = ntohl(*((unsigned long *)dp)); sunatm->vci = htons((rawatm >> 4) & 0xffff); sunatm->vpi = (rawatm >> 20) & 0x00ff; sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) | ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 : ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 : ((dp[ATM_HDR_SIZE] == 0xaa && dp[ATM_HDR_SIZE+1] == 0xaa && dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1))); } else { packet_len -= ATM_HDR_SIZE; caplen -= ATM_HDR_SIZE; dp += ATM_HDR_SIZE; } break; case TYPE_COLOR_HASH_ETH: case TYPE_DSM_COLOR_ETH: case TYPE_COLOR_ETH: case TYPE_ETH: packet_len = ntohs(header->wlen); packet_len -= (pd->dag_fcs_bits >> 3); caplen = rlen - dag_record_size - 2; /* Skip over extension headers */ caplen -= (8 * num_ext_hdr); if (caplen > packet_len) { caplen = packet_len; } dp += 2; break; case TYPE_COLOR_HASH_POS: case TYPE_DSM_COLOR_HDLC_POS: case TYPE_COLOR_HDLC_POS: case TYPE_HDLC_POS: packet_len = ntohs(header->wlen); packet_len -= (pd->dag_fcs_bits >> 3); caplen = rlen - dag_record_size; /* Skip over extension headers */ caplen -= (8 * num_ext_hdr); if (caplen > packet_len) { caplen = packet_len; } break; case TYPE_COLOR_MC_HDLC_POS: case TYPE_MC_HDLC: packet_len = ntohs(header->wlen); packet_len -= (pd->dag_fcs_bits >> 3); caplen = rlen - dag_record_size - 4; /* Skip over extension headers */ caplen -= (8 * num_ext_hdr); if (caplen > packet_len) { caplen = packet_len; } /* jump the MC_HDLC_HEADER */ dp += 4; #ifdef DLT_MTP2_WITH_PHDR if (p->linktype == DLT_MTP2_WITH_PHDR) { /* Add the MTP2 Pseudo Header */ caplen += MTP2_HDR_LEN; packet_len += MTP2_HDR_LEN; TempPkt[MTP2_SENT_OFFSET] = 0; TempPkt[MTP2_ANNEX_A_USED_OFFSET] = MTP2_ANNEX_A_USED_UNKNOWN; *(TempPkt+MTP2_LINK_NUMBER_OFFSET) = ((header->rec.mc_hdlc.mc_header>>16)&0x01); *(TempPkt+MTP2_LINK_NUMBER_OFFSET+1) = ((header->rec.mc_hdlc.mc_header>>24)&0xff); memcpy(TempPkt+MTP2_HDR_LEN, dp, caplen); dp = TempPkt; } #endif break; case TYPE_IPV4: case TYPE_IPV6: packet_len = ntohs(header->wlen); caplen = rlen - dag_record_size; /* Skip over extension headers */ caplen -= (8 * num_ext_hdr); if (caplen > packet_len) { caplen = packet_len; } break; /* These types have no matching 'native' DLT, but can be used with DLT_ERF above */ case TYPE_MC_RAW: case TYPE_MC_RAW_CHANNEL: case TYPE_IP_COUNTER: case TYPE_TCP_FLOW_COUNTER: case TYPE_INFINIBAND: case TYPE_RAW_LINK: case TYPE_INFINIBAND_LINK: default: /* Unhandled ERF type. * Ignore rather than generating error */ continue; } /* switch type */ } /* ERF encapsulation */ if (caplen > p->snapshot) caplen = p->snapshot; /* Run the packet filter if there is one. */ if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { /* convert between timestamp formats */ register unsigned long long ts; if (IS_BIGENDIAN()) { ts = SWAPLL(header->ts); } else { ts = header->ts; } switch (p->opt.tstamp_precision) { case PCAP_TSTAMP_PRECISION_NANO: ticks_per_second = 1000000000; break; case PCAP_TSTAMP_PRECISION_MICRO: default: ticks_per_second = 1000000; break; } pcap_header.ts.tv_sec = ts >> 32; ts = (ts & 0xffffffffULL) * ticks_per_second; ts += 0x80000000; /* rounding */ pcap_header.ts.tv_usec = ts >> 32; if (pcap_header.ts.tv_usec >= ticks_per_second) { pcap_header.ts.tv_usec -= ticks_per_second; pcap_header.ts.tv_sec++; } /* Fill in our own header data */ pcap_header.caplen = caplen; pcap_header.len = packet_len; /* Count the packet. */ pd->stat.ps_recv++; /* Call the user supplied callback function */ callback(user, &pcap_header, dp); /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */ processed++; if (processed == cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { /* Reached the user-specified limit. */ return cnt; } } } return processed; } static int dag_inject(pcap_t *p, const void *buf _U_, size_t size _U_) { strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", PCAP_ERRBUF_SIZE); return (-1); } /* * Get a handle for a live capture from the given DAG device. Passing a NULL * device will result in a failure. The promisc flag is ignored because DAG * cards are always promiscuous. The to_ms parameter is used in setting the * API polling parameters. * * snaplen is now also ignored, until we get per-stream slen support. Set * slen with approprite DAG tool BEFORE pcap_activate(). * * See also pcap(3). */ static int dag_activate(pcap_t* handle) { struct pcap_dag *handlep = handle->priv; #if 0 char conf[30]; /* dag configure string */ #endif char *s; int n; daginf_t* daginf; char * newDev = NULL; char * device = handle->opt.device; #ifdef HAVE_DAG_STREAMS_API uint32_t mindata; struct timeval maxwait; struct timeval poll; #endif if (device == NULL) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno)); return -1; } /* Initialize some components of the pcap structure. */ #ifdef HAVE_DAG_STREAMS_API newDev = (char *)malloc(strlen(device) + 16); if (newDev == NULL) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s", pcap_strerror(errno)); goto fail; } /* Parse input name to get dag device and stream number if provided */ if (dag_parse_name(device, newDev, strlen(device) + 16, &handlep->dag_stream) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: %s", pcap_strerror(errno)); goto fail; } device = newDev; if (handlep->dag_stream%2) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture"); goto fail; } #else if (strncmp(device, "/dev/", 5) != 0) { newDev = (char *)malloc(strlen(device) + 5); if (newDev == NULL) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s", pcap_strerror(errno)); goto fail; } strcpy(newDev, "/dev/"); strcat(newDev, device); device = newDev; } #endif /* HAVE_DAG_STREAMS_API */ /* setup device parameters */ if((handle->fd = dag_open((char *)device)) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno)); goto fail; } #ifdef HAVE_DAG_STREAMS_API /* Open requested stream. Can fail if already locked or on error */ if (dag_attach_stream(handle->fd, handlep->dag_stream, 0, 0) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_attach_stream: %s", pcap_strerror(errno)); goto failclose; } /* Set up default poll parameters for stream * Can be overridden by pcap_set_nonblock() */ if (dag_get_stream_poll(handle->fd, handlep->dag_stream, &mindata, &maxwait, &poll) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s", pcap_strerror(errno)); goto faildetach; } if (handle->opt.immediate) { /* Call callback immediately. * XXX - is this the right way to handle this? */ mindata = 0; } else { /* Amount of data to collect in Bytes before calling callbacks. * Important for efficiency, but can introduce latency * at low packet rates if to_ms not set! */ mindata = 65536; } /* Obey opt.timeout (was to_ms) if supplied. This is a good idea! * Recommend 10-100ms. Calls will time out even if no data arrived. */ maxwait.tv_sec = handle->opt.timeout/1000; maxwait.tv_usec = (handle->opt.timeout%1000) * 1000; if (dag_set_stream_poll(handle->fd, handlep->dag_stream, mindata, &maxwait, &poll) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s", pcap_strerror(errno)); goto faildetach; } #else if((handlep->dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s", device, pcap_strerror(errno)); goto failclose; } #endif /* HAVE_DAG_STREAMS_API */ /* XXX Not calling dag_configure() to set slen; this is unsafe in * multi-stream environments as the gpp config is global. * Once the firmware provides 'per-stream slen' this can be supported * again via the Config API without side-effects */ #if 0 /* set the card snap length to the specified snaplen parameter */ /* This is a really bad idea, as different cards have different * valid slen ranges. Should fix in Config API. */ if (handle->snapshot == 0 || handle->snapshot > MAX_DAG_SNAPLEN) { handle->snapshot = MAX_DAG_SNAPLEN; } else if (snaplen < MIN_DAG_SNAPLEN) { handle->snapshot = MIN_DAG_SNAPLEN; } /* snap len has to be a multiple of 4 */ pcap_snprintf(conf, 30, "varlen slen=%d", (snaplen + 3) & ~3); if(dag_configure(handle->fd, conf) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s", device, pcap_strerror(errno)); goto faildetach; } #endif #ifdef HAVE_DAG_STREAMS_API if(dag_start_stream(handle->fd, handlep->dag_stream) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start_stream %s: %s", device, pcap_strerror(errno)); goto faildetach; } #else if(dag_start(handle->fd) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s", device, pcap_strerror(errno)); goto failclose; } #endif /* HAVE_DAG_STREAMS_API */ /* * Important! You have to ensure bottom is properly * initialized to zero on startup, it won't give you * a compiler warning if you make this mistake! */ handlep->dag_mem_bottom = 0; handlep->dag_mem_top = 0; /* * Find out how many FCS bits we should strip. * First, query the card to see if it strips the FCS. */ daginf = dag_info(handle->fd); if ((0x4200 == daginf->device_code) || (0x4230 == daginf->device_code)) { /* DAG 4.2S and 4.23S already strip the FCS. Stripping the final word again truncates the packet. */ handlep->dag_fcs_bits = 0; /* Note that no FCS will be supplied. */ handle->linktype_ext = LT_FCS_DATALINK_EXT(0); } else { /* * Start out assuming it's 32 bits. */ handlep->dag_fcs_bits = 32; /* Allow an environment variable to override. */ if ((s = getenv("ERF_FCS_BITS")) != NULL) { if ((n = atoi(s)) == 0 || n == 16 || n == 32) { handlep->dag_fcs_bits = n; } else { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment", device, n); goto failstop; } } /* * Did the user request that they not be stripped? */ if ((s = getenv("ERF_DONT_STRIP_FCS")) != NULL) { /* Yes. Note the number of bytes that will be supplied. */ handle->linktype_ext = LT_FCS_DATALINK_EXT(handlep->dag_fcs_bits/16); /* And don't strip them. */ handlep->dag_fcs_bits = 0; } } handlep->dag_timeout = handle->opt.timeout; handle->linktype = -1; if (dag_get_datalink(handle) < 0) goto failstop; handle->bufsize = 0; if (new_pcap_dag(handle) < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s", device, pcap_strerror(errno)); goto failstop; } /* * "select()" and "poll()" don't work on DAG device descriptors. */ handle->selectable_fd = -1; if (newDev != NULL) { free((char *)newDev); } handle->read_op = dag_read; handle->inject_op = dag_inject; handle->setfilter_op = dag_setfilter; handle->setdirection_op = NULL; /* Not implemented.*/ handle->set_datalink_op = dag_set_datalink; handle->getnonblock_op = pcap_getnonblock_fd; handle->setnonblock_op = dag_setnonblock; handle->stats_op = dag_stats; handle->cleanup_op = dag_platform_cleanup; handlep->stat.ps_drop = 0; handlep->stat.ps_recv = 0; handlep->stat.ps_ifdrop = 0; return 0; #ifdef HAVE_DAG_STREAMS_API failstop: if (dag_stop_stream(handle->fd, handlep->dag_stream) < 0) { fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); } faildetach: if (dag_detach_stream(handle->fd, handlep->dag_stream) < 0) fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); #else failstop: if (dag_stop(handle->fd) < 0) fprintf(stderr,"dag_stop: %s\n", strerror(errno)); #endif /* HAVE_DAG_STREAMS_API */ failclose: if (dag_close(handle->fd) < 0) fprintf(stderr,"dag_close: %s\n", strerror(errno)); delete_pcap_dag(handle); fail: pcap_cleanup_live_common(handle); if (newDev != NULL) { free((char *)newDev); } return PCAP_ERROR; } pcap_t *dag_create(const char *device, char *ebuf, int *is_ours) { const char *cp; char *cpend; long devnum; pcap_t *p; #ifdef HAVE_DAG_STREAMS_API long stream = 0; #endif /* Does this look like a DAG device? */ cp = strrchr(device, '/'); if (cp == NULL) cp = device; /* Does it begin with "dag"? */ if (strncmp(cp, "dag", 3) != 0) { /* Nope, doesn't begin with "dag" */ *is_ours = 0; return NULL; } /* Yes - is "dag" followed by a number from 0 to DAG_MAX_BOARDS-1 */ cp += 3; devnum = strtol(cp, &cpend, 10); #ifdef HAVE_DAG_STREAMS_API if (*cpend == ':') { /* Followed by a stream number. */ stream = strtol(++cpend, &cpend, 10); } #endif if (cpend == cp || *cpend != '\0') { /* Not followed by a number. */ *is_ours = 0; return NULL; } if (devnum < 0 || devnum >= DAG_MAX_BOARDS) { /* Followed by a non-valid number. */ *is_ours = 0; return NULL; } #ifdef HAVE_DAG_STREAMS_API if (stream <0 || stream >= DAG_STREAM_MAX) { /* Followed by a non-valid stream number. */ *is_ours = 0; return NULL; } #endif /* OK, it's probably ours. */ *is_ours = 1; p = pcap_create_common(ebuf, sizeof (struct pcap_dag)); if (p == NULL) return NULL; p->activate_op = dag_activate; /* * We claim that we support microsecond and nanosecond time * stamps. * * XXX Our native precision is 2^-32s, but libpcap doesn't support * power of two precisions yet. We can convert to either MICRO or NANO. */ p->tstamp_precision_count = 2; p->tstamp_precision_list = malloc(2 * sizeof(u_int)); if (p->tstamp_precision_list == NULL) { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); pcap_close(p); return NULL; } p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; return p; } static int dag_stats(pcap_t *p, struct pcap_stat *ps) { struct pcap_dag *pd = p->priv; /* This needs to be filled out correctly. Hopefully a dagapi call will provide all necessary information. */ /*pd->stat.ps_recv = 0;*/ /*pd->stat.ps_drop = 0;*/ *ps = pd->stat; return 0; } /* * Previously we just generated a list of all possible names and let * pcap_add_if() attempt to open each one, but with streams this adds up * to 81 possibilities which is inefficient. * * Since we know more about the devices we can prune the tree here. * pcap_add_if() will still retest each device but the total number of * open attempts will still be much less than the naive approach. */ int dag_findalldevs(pcap_if_t **devlistp, char *errbuf) { char name[12]; /* XXX - pick a size */ int ret = 0; int c; char dagname[DAGNAME_BUFSIZE]; int dagstream; int dagfd; dag_card_inf_t *inf; char *description; /* Try all the DAGs 0-DAG_MAX_BOARDS */ for (c = 0; c < DAG_MAX_BOARDS; c++) { pcap_snprintf(name, 12, "dag%d", c); if (-1 == dag_parse_name(name, dagname, DAGNAME_BUFSIZE, &dagstream)) { return -1; } description = NULL; if ( (dagfd = dag_open(dagname)) >= 0 ) { if ((inf = dag_pciinfo(dagfd))) description = dag_device_name(inf->device_code, 1); if (pcap_add_if(devlistp, name, 0, description, errbuf) == -1) { /* * Failure. */ ret = -1; } #ifdef HAVE_DAG_STREAMS_API { int stream, rxstreams; rxstreams = dag_rx_get_stream_count(dagfd); for(stream=0;streamerrbuf, "setfilter: No filter specified", sizeof(p->errbuf)); return -1; } /* Make our private copy of the filter */ if (install_bpf_program(p, fp) < 0) return -1; return (0); } static int dag_set_datalink(pcap_t *p, int dlt) { p->linktype = dlt; return (0); } static int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf) { struct pcap_dag *pd = p->priv; /* * Set non-blocking mode on the FD. * XXX - is that necessary? If not, don't bother calling it, * and have a "dag_getnonblock()" function that looks at * "pd->dag_offset_flags". */ if (pcap_setnonblock_fd(p, nonblock, errbuf) < 0) return (-1); #ifdef HAVE_DAG_STREAMS_API { uint32_t mindata; struct timeval maxwait; struct timeval poll; if (dag_get_stream_poll(p->fd, pd->dag_stream, &mindata, &maxwait, &poll) < 0) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s", pcap_strerror(errno)); return -1; } /* Amount of data to collect in Bytes before calling callbacks. * Important for efficiency, but can introduce latency * at low packet rates if to_ms not set! */ if(nonblock) mindata = 0; else mindata = 65536; if (dag_set_stream_poll(p->fd, pd->dag_stream, mindata, &maxwait, &poll) < 0) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s", pcap_strerror(errno)); return -1; } } #endif /* HAVE_DAG_STREAMS_API */ if (nonblock) { pd->dag_offset_flags |= DAGF_NONBLOCK; } else { pd->dag_offset_flags &= ~DAGF_NONBLOCK; } return (0); } static int dag_get_datalink(pcap_t *p) { struct pcap_dag *pd = p->priv; int index=0, dlt_index=0; uint8_t types[255]; memset(types, 0, 255); if (p->dlt_list == NULL && (p->dlt_list = malloc(255*sizeof(*(p->dlt_list)))) == NULL) { (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); return (-1); } p->linktype = 0; #ifdef HAVE_DAG_GET_STREAM_ERF_TYPES /* Get list of possible ERF types for this card */ if (dag_get_stream_erf_types(p->fd, pd->dag_stream, types, 255) < 0) { pcap_snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_stream_erf_types: %s", pcap_strerror(errno)); return (-1); } while (types[index]) { #elif defined HAVE_DAG_GET_ERF_TYPES /* Get list of possible ERF types for this card */ if (dag_get_erf_types(p->fd, types, 255) < 0) { pcap_snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_erf_types: %s", pcap_strerror(errno)); return (-1); } while (types[index]) { #else /* Check the type through a dagapi call. */ types[index] = dag_linktype(p->fd); { #endif switch((types[index] & 0x7f)) { case TYPE_HDLC_POS: case TYPE_COLOR_HDLC_POS: case TYPE_DSM_COLOR_HDLC_POS: case TYPE_COLOR_HASH_POS: if (p->dlt_list != NULL) { p->dlt_list[dlt_index++] = DLT_CHDLC; p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; p->dlt_list[dlt_index++] = DLT_FRELAY; } if(!p->linktype) p->linktype = DLT_CHDLC; break; case TYPE_ETH: case TYPE_COLOR_ETH: case TYPE_DSM_COLOR_ETH: case TYPE_COLOR_HASH_ETH: /* * This is (presumably) a real Ethernet capture; give it a * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so * that an application can let you choose it, in case you're * capturing DOCSIS traffic that a Cisco Cable Modem * Termination System is putting out onto an Ethernet (it * doesn't put an Ethernet header onto the wire, it puts raw * DOCSIS frames out on the wire inside the low-level * Ethernet framing). */ if (p->dlt_list != NULL) { p->dlt_list[dlt_index++] = DLT_EN10MB; p->dlt_list[dlt_index++] = DLT_DOCSIS; } if(!p->linktype) p->linktype = DLT_EN10MB; break; case TYPE_ATM: case TYPE_AAL5: case TYPE_MC_ATM: case TYPE_MC_AAL5: if (p->dlt_list != NULL) { p->dlt_list[dlt_index++] = DLT_ATM_RFC1483; p->dlt_list[dlt_index++] = DLT_SUNATM; } if(!p->linktype) p->linktype = DLT_ATM_RFC1483; break; case TYPE_COLOR_MC_HDLC_POS: case TYPE_MC_HDLC: if (p->dlt_list != NULL) { p->dlt_list[dlt_index++] = DLT_CHDLC; p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; p->dlt_list[dlt_index++] = DLT_FRELAY; p->dlt_list[dlt_index++] = DLT_MTP2; p->dlt_list[dlt_index++] = DLT_MTP2_WITH_PHDR; p->dlt_list[dlt_index++] = DLT_LAPD; } if(!p->linktype) p->linktype = DLT_CHDLC; break; case TYPE_IPV4: case TYPE_IPV6: if(!p->linktype) p->linktype = DLT_RAW; break; case TYPE_LEGACY: case TYPE_MC_RAW: case TYPE_MC_RAW_CHANNEL: case TYPE_IP_COUNTER: case TYPE_TCP_FLOW_COUNTER: case TYPE_INFINIBAND: case TYPE_RAW_LINK: case TYPE_INFINIBAND_LINK: default: /* Libpcap cannot deal with these types yet */ /* Add no 'native' DLTs, but still covered by DLT_ERF */ break; } /* switch */ index++; } p->dlt_list[dlt_index++] = DLT_ERF; p->dlt_count = dlt_index; if(!p->linktype) p->linktype = DLT_ERF; return p->linktype; } #ifdef DAG_ONLY /* * This libpcap build supports only DAG cards, not regular network * interfaces. */ /* * There are no regular interfaces, just DAG interfaces. */ int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { *alldevsp = NULL; return (0); } /* * Attempts to open a regular interface fail. */ pcap_t * pcap_create_interface(const char *device, char *errbuf) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "This version of libpcap only supports DAG cards"); return NULL; } #endif libpcap-1.8.1/pcap_open_live.3pcap0000644000026300017510000000507113003771737015204 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_OPEN_LIVE 3PCAP "3 January 2014" .SH NAME pcap_open_live \- open a device for capturing .SH SYNOPSIS .nf .ft B #include .ft .LP .nf .ft B char errbuf[PCAP_ERRBUF_SIZE]; .ft .LP .ft B pcap_t *pcap_open_live(const char *device, int snaplen, .ti +8 int promisc, int to_ms, char *errbuf); .ft .fi .SH DESCRIPTION .B pcap_open_live() is used to obtain a packet capture handle to look at packets on the network. .I device is a string that specifies the network device to open; on Linux systems with 2.2 or later kernels, a .I device argument of "any" or .B NULL can be used to capture packets from all interfaces. .PP .I snaplen specifies the snapshot length to be set on the handle. .PP .I promisc specifies if the interface is to be put into promiscuous mode. .PP .I to_ms specifies the read timeout in milliseconds. .SH RETURN VALUE .B pcap_open_live() returns a .I pcap_t * on success and .B NULL on failure. If .B NULL is returned, .I errbuf is filled in with an appropriate error message. .I errbuf may also be set to warning text when .B pcap_open_live() succeeds; to detect this case the caller should store a zero-length string in .I errbuf before calling .B pcap_open_live() and display the warning to the user if .I errbuf is no longer a zero-length string. .I errbuf is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) libpcap-1.8.1/pcap-int.h0000644000026300017510000003545613003771737013167 0ustar mcrmcr/* * Copyright (c) 1994, 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef pcap_int_h #define pcap_int_h #include #ifdef __cplusplus extern "C" { #endif #if defined(_WIN32) /* * Make sure Packet32.h doesn't define BPF structures that we've * probably already defined as a result of including . */ #define BPF_MAJOR_VERSION #include #elif defined(MSDOS) #include #include #endif #if (defined(_MSC_VER) && (_MSC_VER <= 1200)) /* we are compiling with Visual Studio 6, that doesn't support the LL suffix*/ /* * Swap byte ordering of unsigned long long timestamp on a big endian * machine. */ #define SWAPLL(ull) ((ull & 0xff00000000000000) >> 56) | \ ((ull & 0x00ff000000000000) >> 40) | \ ((ull & 0x0000ff0000000000) >> 24) | \ ((ull & 0x000000ff00000000) >> 8) | \ ((ull & 0x00000000ff000000) << 8) | \ ((ull & 0x0000000000ff0000) << 24) | \ ((ull & 0x000000000000ff00) << 40) | \ ((ull & 0x00000000000000ff) << 56) #else /* A recent Visual studio compiler or not VC */ /* * Swap byte ordering of unsigned long long timestamp on a big endian * machine. */ #define SWAPLL(ull) ((ull & 0xff00000000000000LL) >> 56) | \ ((ull & 0x00ff000000000000LL) >> 40) | \ ((ull & 0x0000ff0000000000LL) >> 24) | \ ((ull & 0x000000ff00000000LL) >> 8) | \ ((ull & 0x00000000ff000000LL) << 8) | \ ((ull & 0x0000000000ff0000LL) << 24) | \ ((ull & 0x000000000000ff00LL) << 40) | \ ((ull & 0x00000000000000ffLL) << 56) #endif /* _MSC_VER */ /* * Maximum snapshot length. * * Somewhat arbitrary, but chosen to be: * * 1) big enough for maximum-size Linux loopback packets (65549) * and some USB packets captured with USBPcap: * * http://desowin.org/usbpcap/ * * (> 131072, < 262144) * * and * * 2) small enough not to cause attempts to allocate huge amounts of * memory; some applications might use the snapshot length in a * savefile header to control the size of the buffer they allocate, * so a size of, say, 2^31-1 might not work well. * * We don't enforce this in pcap_set_snaplen(), but we use it internally. */ #define MAXIMUM_SNAPLEN 262144 struct pcap_opt { char *device; int timeout; /* timeout for buffering */ u_int buffer_size; int promisc; int rfmon; /* monitor mode */ int immediate; /* immediate mode - deliver packets as soon as they arrive */ int tstamp_type; int tstamp_precision; }; typedef int (*activate_op_t)(pcap_t *); typedef int (*can_set_rfmon_op_t)(pcap_t *); typedef int (*read_op_t)(pcap_t *, int cnt, pcap_handler, u_char *); typedef int (*inject_op_t)(pcap_t *, const void *, size_t); typedef int (*setfilter_op_t)(pcap_t *, struct bpf_program *); typedef int (*setdirection_op_t)(pcap_t *, pcap_direction_t); typedef int (*set_datalink_op_t)(pcap_t *, int); typedef int (*getnonblock_op_t)(pcap_t *, char *); typedef int (*setnonblock_op_t)(pcap_t *, int, char *); typedef int (*stats_op_t)(pcap_t *, struct pcap_stat *); #ifdef _WIN32 typedef struct pcap_stat *(*stats_ex_op_t)(pcap_t *, int *); typedef int (*setbuff_op_t)(pcap_t *, int); typedef int (*setmode_op_t)(pcap_t *, int); typedef int (*setmintocopy_op_t)(pcap_t *, int); typedef HANDLE (*getevent_op_t)(pcap_t *); typedef int (*oid_get_request_op_t)(pcap_t *, bpf_u_int32, void *, size_t *); typedef int (*oid_set_request_op_t)(pcap_t *, bpf_u_int32, const void *, size_t *); typedef u_int (*sendqueue_transmit_op_t)(pcap_t *, pcap_send_queue *, int); typedef int (*setuserbuffer_op_t)(pcap_t *, int); typedef int (*live_dump_op_t)(pcap_t *, char *, int, int); typedef int (*live_dump_ended_op_t)(pcap_t *, int); typedef PAirpcapHandle (*get_airpcap_handle_op_t)(pcap_t *); #endif typedef void (*cleanup_op_t)(pcap_t *); /* * We put all the stuff used in the read code path at the beginning, * to try to keep it together in the same cache line or lines. */ struct pcap { /* * Method to call to read packets on a live capture. */ read_op_t read_op; /* * Method to call to read packets from a savefile. */ int (*next_packet_op)(pcap_t *, struct pcap_pkthdr *, u_char **); #ifdef _WIN32 ADAPTER *adapter; #else int fd; int selectable_fd; #endif /* _WIN32 */ /* * Read buffer. */ u_int bufsize; void *buffer; u_char *bp; int cc; int break_loop; /* flag set to force break from packet-reading loop */ void *priv; /* private data for methods */ int swapped; FILE *rfile; /* null if live capture, non-null if savefile */ u_int fddipad; struct pcap *next; /* list of open pcaps that need stuff cleared on close */ /* * File version number; meaningful only for a savefile, but we * keep it here so that apps that (mistakenly) ask for the * version numbers will get the same zero values that they * always did. */ int version_major; int version_minor; int snapshot; int linktype; /* Network linktype */ int linktype_ext; /* Extended information stored in the linktype field of a file */ int tzoff; /* timezone offset */ int offset; /* offset for proper alignment */ int activated; /* true if the capture is really started */ int oldstyle; /* if we're opening with pcap_open_live() */ struct pcap_opt opt; /* * Place holder for pcap_next(). */ u_char *pkt; #ifdef _WIN32 struct pcap_stat stat; /* used for pcap_stats_ex() */ #endif /* We're accepting only packets in this direction/these directions. */ pcap_direction_t direction; /* * Flags to affect BPF code generation. */ int bpf_codegen_flags; /* * Placeholder for filter code if bpf not in kernel. */ struct bpf_program fcode; char errbuf[PCAP_ERRBUF_SIZE + 1]; int dlt_count; u_int *dlt_list; int tstamp_type_count; u_int *tstamp_type_list; int tstamp_precision_count; u_int *tstamp_precision_list; struct pcap_pkthdr pcap_header; /* This is needed for the pcap_next_ex() to work */ /* * More methods. */ activate_op_t activate_op; can_set_rfmon_op_t can_set_rfmon_op; inject_op_t inject_op; setfilter_op_t setfilter_op; setdirection_op_t setdirection_op; set_datalink_op_t set_datalink_op; getnonblock_op_t getnonblock_op; setnonblock_op_t setnonblock_op; stats_op_t stats_op; /* * Routine to use as callback for pcap_next()/pcap_next_ex(). */ pcap_handler oneshot_callback; #ifdef _WIN32 /* * These are, at least currently, specific to the Win32 NPF * driver. */ stats_ex_op_t stats_ex_op; setbuff_op_t setbuff_op; setmode_op_t setmode_op; setmintocopy_op_t setmintocopy_op; getevent_op_t getevent_op; oid_get_request_op_t oid_get_request_op; oid_set_request_op_t oid_set_request_op; sendqueue_transmit_op_t sendqueue_transmit_op; setuserbuffer_op_t setuserbuffer_op; live_dump_op_t live_dump_op; live_dump_ended_op_t live_dump_ended_op; get_airpcap_handle_op_t get_airpcap_handle_op; #endif cleanup_op_t cleanup_op; }; /* * BPF code generation flags. */ #define BPF_SPECIAL_VLAN_HANDLING 0x00000001 /* special VLAN handling for Linux */ /* * This is a timeval as stored in a savefile. * It has to use the same types everywhere, independent of the actual * `struct timeval'; `struct timeval' has 32-bit tv_sec values on some * platforms and 64-bit tv_sec values on other platforms, and writing * out native `struct timeval' values would mean files could only be * read on systems with the same tv_sec size as the system on which * the file was written. */ struct pcap_timeval { bpf_int32 tv_sec; /* seconds */ bpf_int32 tv_usec; /* microseconds */ }; /* * This is a `pcap_pkthdr' as actually stored in a savefile. * * Do not change the format of this structure, in any way (this includes * changes that only affect the length of fields in this structure), * and do not make the time stamp anything other than seconds and * microseconds (e.g., seconds and nanoseconds). Instead: * * introduce a new structure for the new format; * * send mail to "tcpdump-workers@lists.tcpdump.org", requesting * a new magic number for your new capture file format, and, when * you get the new magic number, put it in "savefile.c"; * * use that magic number for save files with the changed record * header; * * make the code in "savefile.c" capable of reading files with * the old record header as well as files with the new record header * (using the magic number to determine the header format). * * Then supply the changes by forking the branch at * * https://github.com/the-tcpdump-group/libpcap/issues * * and issuing a pull request, so that future versions of libpcap and * programs that use it (such as tcpdump) will be able to read your new * capture file format. */ struct pcap_sf_pkthdr { struct pcap_timeval ts; /* time stamp */ bpf_u_int32 caplen; /* length of portion present */ bpf_u_int32 len; /* length this packet (off wire) */ }; /* * How a `pcap_pkthdr' is actually stored in savefiles written * by some patched versions of libpcap (e.g. the ones in Red * Hat Linux 6.1 and 6.2). * * Do not change the format of this structure, in any way (this includes * changes that only affect the length of fields in this structure). * Instead, introduce a new structure, as per the above. */ struct pcap_sf_patched_pkthdr { struct pcap_timeval ts; /* time stamp */ bpf_u_int32 caplen; /* length of portion present */ bpf_u_int32 len; /* length this packet (off wire) */ int index; unsigned short protocol; unsigned char pkt_type; }; /* * User data structure for the one-shot callback used for pcap_next() * and pcap_next_ex(). */ struct oneshot_userdata { struct pcap_pkthdr *hdr; const u_char **pkt; pcap_t *pd; }; #ifndef min #define min(a, b) ((a) > (b) ? (b) : (a)) #endif int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *); #include #include "portability.h" /* * Does the packet count argument to a module's read routine say * "supply packets until you run out of packets"? */ #define PACKET_COUNT_IS_UNLIMITED(count) ((count) <= 0) /* * Routines that most pcap implementations can use for non-blocking mode. */ #if !defined(_WIN32) && !defined(MSDOS) int pcap_getnonblock_fd(pcap_t *, char *); int pcap_setnonblock_fd(pcap_t *p, int, char *); #endif /* * Internal interfaces for "pcap_create()". * * "pcap_create_interface()" is the routine to do a pcap_create on * a regular network interface. There are multiple implementations * of this, one for each platform type (Linux, BPF, DLPI, etc.), * with the one used chosen by the configure script. * * "pcap_create_common()" allocates and fills in a pcap_t, for use * by pcap_create routines. */ pcap_t *pcap_create_interface(const char *, char *); pcap_t *pcap_create_common(char *, size_t); int pcap_do_addexit(pcap_t *); void pcap_add_to_pcaps_to_close(pcap_t *); void pcap_remove_from_pcaps_to_close(pcap_t *); void pcap_cleanup_live_common(pcap_t *); int pcap_check_activated(pcap_t *); /* * Internal interfaces for "pcap_findalldevs()". * * "pcap_platform_finddevs()" is a platform-dependent routine to * find local network interfaces. * * "pcap_findalldevs_interfaces()" is a helper to find those interfaces * using the "standard" mechanisms (SIOCGIFCONF, "getifaddrs()", etc.). * * "pcap_add_if()" adds an interface to the list of interfaces, for * use by various "find interfaces" routines. */ int pcap_platform_finddevs(pcap_if_t **, char *); #if !defined(_WIN32) && !defined(MSDOS) int pcap_findalldevs_interfaces(pcap_if_t **, char *, int (*)(const char *)); #endif int add_addr_to_iflist(pcap_if_t **, const char *, bpf_u_int32, struct sockaddr *, size_t, struct sockaddr *, size_t, struct sockaddr *, size_t, struct sockaddr *, size_t, char *); int add_addr_to_dev(pcap_if_t *, struct sockaddr *, size_t, struct sockaddr *, size_t, struct sockaddr *, size_t, struct sockaddr *dstaddr, size_t, char *errbuf); int pcap_add_if(pcap_if_t **, const char *, bpf_u_int32, const char *, char *); int add_or_find_if(pcap_if_t **, pcap_if_t **, const char *, bpf_u_int32, const char *, char *); #ifndef _WIN32 bpf_u_int32 if_flags_to_pcap_flags(const char *, u_int); #endif /* * Internal interfaces for "pcap_open_offline()". * * "pcap_open_offline_common()" allocates and fills in a pcap_t, for use * by pcap_open_offline routines. * * "sf_cleanup()" closes the file handle associated with a pcap_t, if * appropriate, and frees all data common to all modules for handling * savefile types. */ pcap_t *pcap_open_offline_common(char *ebuf, size_t size); void sf_cleanup(pcap_t *p); /* * Internal interfaces for both "pcap_create()" and routines that * open savefiles. * * "pcap_oneshot()" is the standard one-shot callback for "pcap_next()" * and "pcap_next_ex()". */ void pcap_oneshot(u_char *, const struct pcap_pkthdr *, const u_char *); #ifdef _WIN32 void pcap_win32_err_to_str(DWORD, char *); #endif int install_bpf_program(pcap_t *, struct bpf_program *); int pcap_strcasecmp(const char *, const char *); #ifdef __cplusplus } #endif #endif libpcap-1.8.1/pcap/0000755000026300017510000000000013003775545012212 5ustar mcrmcrlibpcap-1.8.1/pcap/namedb.h0000644000026300017510000000650613003771737013617 0ustar mcrmcr/* * Copyright (c) 1994, 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lib_pcap_namedb_h #define lib_pcap_namedb_h #ifdef __cplusplus extern "C" { #endif /* * As returned by the pcap_next_etherent() * XXX this stuff doesn't belong in this interface, but this * library already must do name to address translation, so * on systems that don't have support for /etc/ethers, we * export these hooks since they're already being used by * some applications (such as tcpdump) and already being * marked as exported in some OSes offering libpcap (such * as Debian). */ struct pcap_etherent { u_char addr[6]; char name[122]; }; #ifndef PCAP_ETHERS_FILE #define PCAP_ETHERS_FILE "/etc/ethers" #endif PCAP_API struct pcap_etherent *pcap_next_etherent(FILE *); PCAP_API u_char *pcap_ether_hostton(const char*); PCAP_API u_char *pcap_ether_aton(const char *); PCAP_API bpf_u_int32 **pcap_nametoaddr(const char *); #ifdef INET6 PCAP_API struct addrinfo *pcap_nametoaddrinfo(const char *); #endif PCAP_API bpf_u_int32 pcap_nametonetaddr(const char *); PCAP_API int pcap_nametoport(const char *, int *, int *); PCAP_API int pcap_nametoportrange(const char *, int *, int *, int *); PCAP_API int pcap_nametoproto(const char *); PCAP_API int pcap_nametoeproto(const char *); PCAP_API int pcap_nametollc(const char *); /* * If a protocol is unknown, PROTO_UNDEF is returned. * Also, pcap_nametoport() returns the protocol along with the port number. * If there are ambiguous entried in /etc/services (i.e. domain * can be either tcp or udp) PROTO_UNDEF is returned. */ #define PROTO_UNDEF -1 #ifdef __cplusplus } #endif #endif libpcap-1.8.1/pcap/can_socketcan.h0000644000026300017510000000456313003771737015165 0ustar mcrmcr/*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lib_pcap_can_socketcan_h #define lib_pcap_can_socketcan_h /* * SocketCAN header, as per Documentation/networking/can.txt in the * Linux source. */ typedef struct { u_int32_t can_id; u_int8_t payload_length; u_int8_t pad; u_int8_t reserved1; u_int8_t reserved2; } pcap_can_socketcan_hdr; #endif libpcap-1.8.1/pcap/dlt.h0000644000026300017510000012507013003771737013152 0ustar mcrmcr/*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)bpf.h 7.1 (Berkeley) 5/7/91 */ #ifndef lib_pcap_dlt_h #define lib_pcap_dlt_h /* * Link-layer header type codes. * * Do *NOT* add new values to this list without asking * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run * the risk of using a value that's already being used for some other * purpose, and of having tools that read libpcap-format captures not * being able to handle captures with your new DLT_ value, with no hope * that they will ever be changed to do so (as that would destroy their * ability to read captures using that value for that other purpose). * * See * * http://www.tcpdump.org/linktypes.html * * for detailed descriptions of some of these link-layer header types. */ /* * These are the types that are the same on all platforms, and that * have been defined by for ages. */ #define DLT_NULL 0 /* BSD loopback encapsulation */ #define DLT_EN10MB 1 /* Ethernet (10Mb) */ #define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ #define DLT_AX25 3 /* Amateur Radio AX.25 */ #define DLT_PRONET 4 /* Proteon ProNET Token Ring */ #define DLT_CHAOS 5 /* Chaos */ #define DLT_IEEE802 6 /* 802.5 Token Ring */ #define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ #define DLT_SLIP 8 /* Serial Line IP */ #define DLT_PPP 9 /* Point-to-point Protocol */ #define DLT_FDDI 10 /* FDDI */ /* * These are types that are different on some platforms, and that * have been defined by for ages. We use #ifdefs to * detect the BSDs that define them differently from the traditional * libpcap * * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, * but I don't know what the right #define is for BSD/OS. */ #define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */ #ifdef __OpenBSD__ #define DLT_RAW 14 /* raw IP */ #else #define DLT_RAW 12 /* raw IP */ #endif /* * Given that the only OS that currently generates BSD/OS SLIP or PPP * is, well, BSD/OS, arguably everybody should have chosen its values * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they * didn't. So it goes. */ #if defined(__NetBSD__) || defined(__FreeBSD__) #ifndef DLT_SLIP_BSDOS #define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ #define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ #endif #else #define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ #define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ #endif /* * 17 was used for DLT_PFLOG in OpenBSD; it no longer is. * * It was DLT_LANE8023 in SuSE 6.3, so we defined LINKTYPE_PFLOG * as 117 so that pflog captures would use a link-layer header type * value that didn't collide with any other values. On all * platforms other than OpenBSD, we defined DLT_PFLOG as 117, * and we mapped between LINKTYPE_PFLOG and DLT_PFLOG. * * OpenBSD eventually switched to using 117 for DLT_PFLOG as well. * * Don't use 17 for anything else. */ /* * 18 is used for DLT_PFSYNC in OpenBSD, NetBSD, DragonFly BSD and * Mac OS X; don't use it for anything else. (FreeBSD uses 121, * which collides with DLT_HHDLC, even though it doesn't use 18 * for anything and doesn't appear to have ever used it for anything.) * * We define it as 18 on those platforms; it is, unfortunately, used * for DLT_CIP in Suse 6.3, so we don't define it as DLT_PFSYNC * in general. As the packet format for it, like that for * DLT_PFLOG, is not only OS-dependent but OS-version-dependent, * we don't support printing it in tcpdump except on OSes that * have the relevant header files, so it's not that useful on * other platforms. */ #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__) #define DLT_PFSYNC 18 #endif #define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ /* * Apparently Redback uses this for its SmartEdge 400/800. I hope * nobody else decided to use it, too. */ #define DLT_REDBACK_SMARTEDGE 32 /* * These values are defined by NetBSD; other platforms should refrain from * using them for other purposes, so that NetBSD savefiles with link * types of 50 or 51 can be read as this type on all platforms. */ #define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ #define DLT_PPP_ETHER 51 /* PPP over Ethernet */ /* * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses * a link-layer type of 99 for the tcpdump it supplies. The link-layer * header has 6 bytes of unknown data, something that appears to be an * Ethernet type, and 36 bytes that appear to be 0 in at least one capture * I've seen. */ #define DLT_SYMANTEC_FIREWALL 99 /* * Values between 100 and 103 are used in capture file headers as * link-layer header type LINKTYPE_ values corresponding to DLT_ types * that differ between platforms; don't use those values for new DLT_ * new types. */ /* * Values starting with 104 are used for newly-assigned link-layer * header type values; for those link-layer header types, the DLT_ * value returned by pcap_datalink() and passed to pcap_open_dead(), * and the LINKTYPE_ value that appears in capture files, are the * same. * * DLT_MATCHING_MIN is the lowest such value; DLT_MATCHING_MAX is * the highest such value. */ #define DLT_MATCHING_MIN 104 /* * This value was defined by libpcap 0.5; platforms that have defined * it with a different value should define it here with that value - * a link type of 104 in a save file will be mapped to DLT_C_HDLC, * whatever value that happens to be, so programs will correctly * handle files with that link type regardless of the value of * DLT_C_HDLC. * * The name DLT_C_HDLC was used by BSD/OS; we use that name for source * compatibility with programs written for BSD/OS. * * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, * for source compatibility with programs written for libpcap 0.5. */ #define DLT_C_HDLC 104 /* Cisco HDLC */ #define DLT_CHDLC DLT_C_HDLC #define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ /* * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, * except when it isn't. (I.e., sometimes it's just raw IP, and * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, * so that we don't have to worry about the link-layer header.) */ /* * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides * with other values. * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header * (DLCI, etc.). */ #define DLT_FRELAY 107 /* * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except * that the AF_ type in the link-layer header is in network byte order. * * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so * we don't use 12 for it in OSes other than OpenBSD. */ #ifdef __OpenBSD__ #define DLT_LOOP 12 #else #define DLT_LOOP 108 #endif /* * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other * than OpenBSD. */ #ifdef __OpenBSD__ #define DLT_ENC 13 #else #define DLT_ENC 109 #endif /* * Values between 110 and 112 are reserved for use in capture file headers * as link-layer types corresponding to DLT_ types that might differ * between platforms; don't use those values for new DLT_ types * other than the corresponding DLT_ types. */ /* * This is for Linux cooked sockets. */ #define DLT_LINUX_SLL 113 /* * Apple LocalTalk hardware. */ #define DLT_LTALK 114 /* * Acorn Econet. */ #define DLT_ECONET 115 /* * Reserved for use with OpenBSD ipfilter. */ #define DLT_IPFILTER 116 /* * OpenBSD DLT_PFLOG. */ #define DLT_PFLOG 117 /* * Registered for Cisco-internal use. */ #define DLT_CISCO_IOS 118 /* * For 802.11 cards using the Prism II chips, with a link-layer * header including Prism monitor mode information plus an 802.11 * header. */ #define DLT_PRISM_HEADER 119 /* * Reserved for Aironet 802.11 cards, with an Aironet link-layer header * (see Doug Ambrisko's FreeBSD patches). */ #define DLT_AIRONET_HEADER 120 /* * Sigh. * * 121 was reserved for Siemens HiPath HDLC on 2002-01-25, as * requested by Tomas Kukosa. * * On 2004-02-25, a FreeBSD checkin to sys/net/bpf.h was made that * assigned 121 as DLT_PFSYNC. In current versions, its libpcap * does DLT_ <-> LINKTYPE_ mapping, mapping DLT_PFSYNC to a * LINKTYPE_PFSYNC value of 246, so it should write out DLT_PFSYNC * dump files with 246 as the link-layer header type. (Earlier * versions might not have done mapping, in which case they would * have written them out with a link-layer header type of 121.) * * OpenBSD, from which pf came, however, uses 18 for DLT_PFSYNC; * its libpcap does no DLT_ <-> LINKTYPE_ mapping, so it would * write out DLT_PFSYNC dump files with use 18 as the link-layer * header type. * * NetBSD, DragonFly BSD, and Darwin also use 18 for DLT_PFSYNC; in * current versions, their libpcaps do DLT_ <-> LINKTYPE_ mapping, * mapping DLT_PFSYNC to a LINKTYPE_PFSYNC value of 246, so they * should write out DLT_PFSYNC dump files with 246 as the link-layer * header type. (Earlier versions might not have done mapping, * in which case they'd work the same way OpenBSD does, writing * them out with a link-layer header type of 18.) * * We'll define DLT_PFSYNC as: * * 18 on NetBSD, OpenBSD, DragonFly BSD, and Darwin; * * 121 on FreeBSD; * * 246 everywhere else. * * We'll define DLT_HHDLC as 121 on everything except for FreeBSD; * anybody who wants to compile, on FreeBSD, code that uses DLT_HHDLC * is out of luck. * * We'll define LINKTYPE_PFSYNC as 246 on *all* platforms, so that * savefiles written using *this* code won't use 18 or 121 for PFSYNC, * they'll all use 246. * * Code that uses pcap_datalink() to determine the link-layer header * type of a savefile won't, when built and run on FreeBSD, be able * to distinguish between LINKTYPE_PFSYNC and LINKTYPE_HHDLC capture * files, as pcap_datalink() will give 121 for both of them. Code * that doesn't, such as the code in Wireshark, will be able to * distinguish between them. * * FreeBSD's libpcap won't map a link-layer header type of 18 - i.e., * DLT_PFSYNC files from OpenBSD and possibly older versions of NetBSD, * DragonFly BSD, and OS X - to DLT_PFSYNC, so code built with FreeBSD's * libpcap won't treat those files as DLT_PFSYNC files. * * Other libpcaps won't map a link-layer header type of 121 to DLT_PFSYNC; * this means they can read DLT_HHDLC files, if any exist, but won't * treat pcap files written by any older versions of FreeBSD libpcap that * didn't map to 246 as DLT_PFSYNC files. */ #ifdef __FreeBSD__ #define DLT_PFSYNC 121 #else #define DLT_HHDLC 121 #endif /* * This is for RFC 2625 IP-over-Fibre Channel. * * This is not for use with raw Fibre Channel, where the link-layer * header starts with a Fibre Channel frame header; it's for IP-over-FC, * where the link-layer header starts with an RFC 2625 Network_Header * field. */ #define DLT_IP_OVER_FC 122 /* * This is for Full Frontal ATM on Solaris with SunATM, with a * pseudo-header followed by an AALn PDU. * * There may be other forms of Full Frontal ATM on other OSes, * with different pseudo-headers. * * If ATM software returns a pseudo-header with VPI/VCI information * (and, ideally, packet type information, e.g. signalling, ILMI, * LANE, LLC-multiplexed traffic, etc.), it should not use * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump * and the like don't have to infer the presence or absence of a * pseudo-header and the form of the pseudo-header. */ #define DLT_SUNATM 123 /* Solaris+SunATM */ /* * Reserved as per request from Kent Dahlgren * for private use. */ #define DLT_RIO 124 /* RapidIO */ #define DLT_PCI_EXP 125 /* PCI Express */ #define DLT_AURORA 126 /* Xilinx Aurora link layer */ /* * Header for 802.11 plus a number of bits of link-layer information * including radio information, used by some recent BSD drivers as * well as the madwifi Atheros driver for Linux. */ #define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ /* * Reserved for the TZSP encapsulation, as per request from * Chris Waters * TZSP is a generic encapsulation for any other link type, * which includes a means to include meta-information * with the packet, e.g. signal strength and channel * for 802.11 packets. */ #define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ /* * BSD's ARCNET headers have the source host, destination host, * and type at the beginning of the packet; that's what's handed * up to userland via BPF. * * Linux's ARCNET headers, however, have a 2-byte offset field * between the host IDs and the type; that's what's handed up * to userland via PF_PACKET sockets. * * We therefore have to have separate DLT_ values for them. */ #define DLT_ARCNET_LINUX 129 /* ARCNET */ /* * Juniper-private data link types, as per request from * Hannes Gredler . The DLT_s are used * for passing on chassis-internal metainformation such as * QOS profiles, etc.. */ #define DLT_JUNIPER_MLPPP 130 #define DLT_JUNIPER_MLFR 131 #define DLT_JUNIPER_ES 132 #define DLT_JUNIPER_GGSN 133 #define DLT_JUNIPER_MFR 134 #define DLT_JUNIPER_ATM2 135 #define DLT_JUNIPER_SERVICES 136 #define DLT_JUNIPER_ATM1 137 /* * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund * . The header that's presented is an Ethernet-like * header: * * #define FIREWIRE_EUI64_LEN 8 * struct firewire_header { * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; * u_char firewire_shost[FIREWIRE_EUI64_LEN]; * u_short firewire_type; * }; * * with "firewire_type" being an Ethernet type value, rather than, * for example, raw GASP frames being handed up. */ #define DLT_APPLE_IP_OVER_IEEE1394 138 /* * Various SS7 encapsulations, as per a request from Jeff Morriss * and subsequent discussions. */ #define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ #define DLT_MTP2 140 /* MTP2, without pseudo-header */ #define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ #define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ /* * DOCSIS MAC frames. */ #define DLT_DOCSIS 143 /* * Linux-IrDA packets. Protocol defined at http://www.irda.org. * Those packets include IrLAP headers and above (IrLMP...), but * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy * framing can be handled by the hardware and depend on the bitrate. * This is exactly the format you would get capturing on a Linux-IrDA * interface (irdaX), but not on a raw serial port. * Note the capture is done in "Linux-cooked" mode, so each packet include * a fake packet header (struct sll_header). This is because IrDA packet * decoding is dependant on the direction of the packet (incomming or * outgoing). * When/if other platform implement IrDA capture, we may revisit the * issue and define a real DLT_IRDA... * Jean II */ #define DLT_LINUX_IRDA 144 /* * Reserved for IBM SP switch and IBM Next Federation switch. */ #define DLT_IBM_SP 145 #define DLT_IBM_SN 146 /* * Reserved for private use. If you have some link-layer header type * that you want to use within your organization, with the capture files * using that link-layer header type not ever be sent outside your * organization, you can use these values. * * No libpcap release will use these for any purpose, nor will any * tcpdump release use them, either. * * Do *NOT* use these in capture files that you expect anybody not using * your private versions of capture-file-reading tools to read; in * particular, do *NOT* use them in products, otherwise you may find that * people won't be able to use tcpdump, or snort, or Ethereal, or... to * read capture files from your firewall/intrusion detection/traffic * monitoring/etc. appliance, or whatever product uses that DLT_ value, * and you may also find that the developers of those applications will * not accept patches to let them read those files. * * Also, do not use them if somebody might send you a capture using them * for *their* private type and tools using them for *your* private type * would have to read them. * * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value, * as per the comment above, and use the type you're given. */ #define DLT_USER0 147 #define DLT_USER1 148 #define DLT_USER2 149 #define DLT_USER3 150 #define DLT_USER4 151 #define DLT_USER5 152 #define DLT_USER6 153 #define DLT_USER7 154 #define DLT_USER8 155 #define DLT_USER9 156 #define DLT_USER10 157 #define DLT_USER11 158 #define DLT_USER12 159 #define DLT_USER13 160 #define DLT_USER14 161 #define DLT_USER15 162 /* * For future use with 802.11 captures - defined by AbsoluteValue * Systems to store a number of bits of link-layer information * including radio information: * * http://www.shaftnet.org/~pizza/software/capturefrm.txt * * but it might be used by some non-AVS drivers now or in the * future. */ #define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ /* * Juniper-private data link type, as per request from * Hannes Gredler . The DLT_s are used * for passing on chassis-internal metainformation such as * QOS profiles, etc.. */ #define DLT_JUNIPER_MONITOR 164 /* * BACnet MS/TP frames. */ #define DLT_BACNET_MS_TP 165 /* * Another PPP variant as per request from Karsten Keil . * * This is used in some OSes to allow a kernel socket filter to distinguish * between incoming and outgoing packets, on a socket intended to * supply pppd with outgoing packets so it can do dial-on-demand and * hangup-on-lack-of-demand; incoming packets are filtered out so they * don't cause pppd to hold the connection up (you don't want random * input packets such as port scans, packets from old lost connections, * etc. to force the connection to stay up). * * The first byte of the PPP header (0xff03) is modified to accomodate * the direction - 0x00 = IN, 0x01 = OUT. */ #define DLT_PPP_PPPD 166 /* * Names for backwards compatibility with older versions of some PPP * software; new software should use DLT_PPP_PPPD. */ #define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD #define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD /* * Juniper-private data link type, as per request from * Hannes Gredler . The DLT_s are used * for passing on chassis-internal metainformation such as * QOS profiles, cookies, etc.. */ #define DLT_JUNIPER_PPPOE 167 #define DLT_JUNIPER_PPPOE_ATM 168 #define DLT_GPRS_LLC 169 /* GPRS LLC */ #define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ #define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ /* * Requested by Oolan Zimmer for use in Gcom's T1/E1 line * monitoring equipment. */ #define DLT_GCOM_T1E1 172 #define DLT_GCOM_SERIAL 173 /* * Juniper-private data link type, as per request from * Hannes Gredler . The DLT_ is used * for internal communication to Physical Interface Cards (PIC) */ #define DLT_JUNIPER_PIC_PEER 174 /* * Link types requested by Gregor Maier of Endace * Measurement Systems. They add an ERF header (see * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of * the link-layer header. */ #define DLT_ERF_ETH 175 /* Ethernet */ #define DLT_ERF_POS 176 /* Packet-over-SONET */ /* * Requested by Daniele Orlandi for raw LAPD * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header * includes additional information before the LAPD header, so it's * not necessarily a generic LAPD header. */ #define DLT_LINUX_LAPD 177 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ are used for prepending meta-information * like interface index, interface name * before standard Ethernet, PPP, Frelay & C-HDLC Frames */ #define DLT_JUNIPER_ETHER 178 #define DLT_JUNIPER_PPP 179 #define DLT_JUNIPER_FRELAY 180 #define DLT_JUNIPER_CHDLC 181 /* * Multi Link Frame Relay (FRF.16) */ #define DLT_MFR 182 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ is used for internal communication with a * voice Adapter Card (PIC) */ #define DLT_JUNIPER_VP 183 /* * Arinc 429 frames. * DLT_ requested by Gianluca Varenni . * Every frame contains a 32bit A429 label. * More documentation on Arinc 429 can be found at * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf */ #define DLT_A429 184 /* * Arinc 653 Interpartition Communication messages. * DLT_ requested by Gianluca Varenni . * Please refer to the A653-1 standard for more information. */ #define DLT_A653_ICM 185 /* * This used to be "USB packets, beginning with a USB setup header; * requested by Paolo Abeni ." * * However, that header didn't work all that well - it left out some * useful information - and was abandoned in favor of the DLT_USB_LINUX * header. * * This is now used by FreeBSD for its BPF taps for USB; that has its * own headers. So it is written, so it is done. * * For source-code compatibility, we also define DLT_USB to have this * value. We do it numerically so that, if code that includes this * file (directly or indirectly) also includes an OS header that also * defines DLT_USB as 186, we don't get a redefinition warning. * (NetBSD 7 does that.) */ #define DLT_USB_FREEBSD 186 #define DLT_USB 186 /* * Bluetooth HCI UART transport layer (part H:4); requested by * Paolo Abeni. */ #define DLT_BLUETOOTH_HCI_H4 187 /* * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz * . */ #define DLT_IEEE802_16_MAC_CPS 188 /* * USB packets, beginning with a Linux USB header; requested by * Paolo Abeni . */ #define DLT_USB_LINUX 189 /* * Controller Area Network (CAN) v. 2.0B packets. * DLT_ requested by Gianluca Varenni . * Used to dump CAN packets coming from a CAN Vector board. * More documentation on the CAN v2.0B frames can be found at * http://www.can-cia.org/downloads/?269 */ #define DLT_CAN20B 190 /* * IEEE 802.15.4, with address fields padded, as is done by Linux * drivers; requested by Juergen Schimmer. */ #define DLT_IEEE802_15_4_LINUX 191 /* * Per Packet Information encapsulated packets. * DLT_ requested by Gianluca Varenni . */ #define DLT_PPI 192 /* * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; * requested by Charles Clancy. */ #define DLT_IEEE802_16_MAC_CPS_RADIO 193 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ is used for internal communication with a * integrated service module (ISM). */ #define DLT_JUNIPER_ISM 194 /* * IEEE 802.15.4, exactly as it appears in the spec (no padding, no * nothing); requested by Mikko Saarnivala . * For this one, we expect the FCS to be present at the end of the frame; * if the frame has no FCS, DLT_IEEE802_15_4_NOFCS should be used. */ #define DLT_IEEE802_15_4 195 /* * Various link-layer types, with a pseudo-header, for SITA * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). */ #define DLT_SITA 196 /* * Various link-layer types, with a pseudo-header, for Endace DAG cards; * encapsulates Endace ERF records. Requested by Stephen Donnelly * . */ #define DLT_ERF 197 /* * Special header prepended to Ethernet packets when capturing from a * u10 Networks board. Requested by Phil Mulholland * . */ #define DLT_RAIF1 198 /* * IPMB packet for IPMI, beginning with the I2C slave address, followed * by the netFn and LUN, etc.. Requested by Chanthy Toeung * . */ #define DLT_IPMB 199 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ is used for capturing data on a secure tunnel interface. */ #define DLT_JUNIPER_ST 200 /* * Bluetooth HCI UART transport layer (part H:4), with pseudo-header * that includes direction information; requested by Paolo Abeni. */ #define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 /* * AX.25 packet with a 1-byte KISS header; see * * http://www.ax25.net/kiss.htm * * as per Richard Stearn . */ #define DLT_AX25_KISS 202 /* * LAPD packets from an ISDN channel, starting with the address field, * with no pseudo-header. * Requested by Varuna De Silva . */ #define DLT_LAPD 203 /* * Variants of various link-layer headers, with a one-byte direction * pseudo-header prepended - zero means "received by this host", * non-zero (any non-zero value) means "sent by this host" - as per * Will Barker . */ #define DLT_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */ #define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ #define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */ #define DLT_LAPB_WITH_DIR 207 /* LAPB */ /* * 208 is reserved for an as-yet-unspecified proprietary link-layer * type, as requested by Will Barker. */ /* * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman * . */ #define DLT_IPMB_LINUX 209 /* * FlexRay automotive bus - http://www.flexray.com/ - as requested * by Hannes Kaelber . */ #define DLT_FLEXRAY 210 /* * Media Oriented Systems Transport (MOST) bus for multimedia * transport - http://www.mostcooperation.com/ - as requested * by Hannes Kaelber . */ #define DLT_MOST 211 /* * Local Interconnect Network (LIN) bus for vehicle networks - * http://www.lin-subbus.org/ - as requested by Hannes Kaelber * . */ #define DLT_LIN 212 /* * X2E-private data link type used for serial line capture, * as requested by Hannes Kaelber . */ #define DLT_X2E_SERIAL 213 /* * X2E-private data link type used for the Xoraya data logger * family, as requested by Hannes Kaelber . */ #define DLT_X2E_XORAYA 214 /* * IEEE 802.15.4, exactly as it appears in the spec (no padding, no * nothing), but with the PHY-level data for non-ASK PHYs (4 octets * of 0 as preamble, one octet of SFD, one octet of frame length+ * reserved bit, and then the MAC-layer data, starting with the * frame control field). * * Requested by Max Filippov . */ #define DLT_IEEE802_15_4_NONASK_PHY 215 /* * David Gibson requested this for * captures from the Linux kernel /dev/input/eventN devices. This * is used to communicate keystrokes and mouse movements from the * Linux kernel to display systems, such as Xorg. */ #define DLT_LINUX_EVDEV 216 /* * GSM Um and Abis interfaces, preceded by a "gsmtap" header. * * Requested by Harald Welte . */ #define DLT_GSMTAP_UM 217 #define DLT_GSMTAP_ABIS 218 /* * MPLS, with an MPLS label as the link-layer header. * Requested by Michele Marchetto on behalf * of OpenBSD. */ #define DLT_MPLS 219 /* * USB packets, beginning with a Linux USB header, with the USB header * padded to 64 bytes; required for memory-mapped access. */ #define DLT_USB_LINUX_MMAPPED 220 /* * DECT packets, with a pseudo-header; requested by * Matthias Wenzel . */ #define DLT_DECT 221 /* * From: "Lidwa, Eric (GSFC-582.0)[SGT INC]" * Date: Mon, 11 May 2009 11:18:30 -0500 * * DLT_AOS. We need it for AOS Space Data Link Protocol. * I have already written dissectors for but need an OK from * legal before I can submit a patch. * */ #define DLT_AOS 222 /* * Wireless HART (Highway Addressable Remote Transducer) * From the HART Communication Foundation * IES/PAS 62591 * * Requested by Sam Roberts . */ #define DLT_WIHART 223 /* * Fibre Channel FC-2 frames, beginning with a Frame_Header. * Requested by Kahou Lei . */ #define DLT_FC_2 224 /* * Fibre Channel FC-2 frames, beginning with an encoding of the * SOF, and ending with an encoding of the EOF. * * The encodings represent the frame delimiters as 4-byte sequences * representing the corresponding ordered sets, with K28.5 * represented as 0xBC, and the D symbols as the corresponding * byte values; for example, SOFi2, which is K28.5 - D21.5 - D1.2 - D21.2, * is represented as 0xBC 0xB5 0x55 0x55. * * Requested by Kahou Lei . */ #define DLT_FC_2_WITH_FRAME_DELIMS 225 /* * Solaris ipnet pseudo-header; requested by Darren Reed . * * The pseudo-header starts with a one-byte version number; for version 2, * the pseudo-header is: * * struct dl_ipnetinfo { * u_int8_t dli_version; * u_int8_t dli_family; * u_int16_t dli_htype; * u_int32_t dli_pktlen; * u_int32_t dli_ifindex; * u_int32_t dli_grifindex; * u_int32_t dli_zsrc; * u_int32_t dli_zdst; * }; * * dli_version is 2 for the current version of the pseudo-header. * * dli_family is a Solaris address family value, so it's 2 for IPv4 * and 26 for IPv6. * * dli_htype is a "hook type" - 0 for incoming packets, 1 for outgoing * packets, and 2 for packets arriving from another zone on the same * machine. * * dli_pktlen is the length of the packet data following the pseudo-header * (so the captured length minus dli_pktlen is the length of the * pseudo-header, assuming the entire pseudo-header was captured). * * dli_ifindex is the interface index of the interface on which the * packet arrived. * * dli_grifindex is the group interface index number (for IPMP interfaces). * * dli_zsrc is the zone identifier for the source of the packet. * * dli_zdst is the zone identifier for the destination of the packet. * * A zone number of 0 is the global zone; a zone number of 0xffffffff * means that the packet arrived from another host on the network, not * from another zone on the same machine. * * An IPv4 or IPv6 datagram follows the pseudo-header; dli_family indicates * which of those it is. */ #define DLT_IPNET 226 /* * CAN (Controller Area Network) frames, with a pseudo-header as supplied * by Linux SocketCAN, and with multi-byte numerical fields in that header * in big-endian byte order. * * See Documentation/networking/can.txt in the Linux source. * * Requested by Felix Obenhuber . */ #define DLT_CAN_SOCKETCAN 227 /* * Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies * whether it's v4 or v6. Requested by Darren Reed . */ #define DLT_IPV4 228 #define DLT_IPV6 229 /* * IEEE 802.15.4, exactly as it appears in the spec (no padding, no * nothing), and with no FCS at the end of the frame; requested by * Jon Smirl . */ #define DLT_IEEE802_15_4_NOFCS 230 /* * Raw D-Bus: * * http://www.freedesktop.org/wiki/Software/dbus * * messages: * * http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages * * starting with the endianness flag, followed by the message type, etc., * but without the authentication handshake before the message sequence: * * http://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol * * Requested by Martin Vidner . */ #define DLT_DBUS 231 /* * Juniper-private data link type, as per request from * Hannes Gredler . */ #define DLT_JUNIPER_VS 232 #define DLT_JUNIPER_SRX_E2E 233 #define DLT_JUNIPER_FIBRECHANNEL 234 /* * DVB-CI (DVB Common Interface for communication between a PC Card * module and a DVB receiver). See * * http://www.kaiser.cx/pcap-dvbci.html * * for the specification. * * Requested by Martin Kaiser . */ #define DLT_DVB_CI 235 /* * Variant of 3GPP TS 27.010 multiplexing protocol (similar to, but * *not* the same as, 27.010). Requested by Hans-Christoph Schemmel * . */ #define DLT_MUX27010 236 /* * STANAG 5066 D_PDUs. Requested by M. Baris Demiray * . */ #define DLT_STANAG_5066_D_PDU 237 /* * Juniper-private data link type, as per request from * Hannes Gredler . */ #define DLT_JUNIPER_ATM_CEMIC 238 /* * NetFilter LOG messages * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets) * * Requested by Jakub Zawadzki */ #define DLT_NFLOG 239 /* * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type * for Ethernet packets with a 4-byte pseudo-header and always * with the payload including the FCS, as supplied by their * netANALYZER hardware and software. * * Requested by Holger P. Frommer */ #define DLT_NETANALYZER 240 /* * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type * for Ethernet packets with a 4-byte pseudo-header and FCS and * with the Ethernet header preceded by 7 bytes of preamble and * 1 byte of SFD, as supplied by their netANALYZER hardware and * software. * * Requested by Holger P. Frommer */ #define DLT_NETANALYZER_TRANSPARENT 241 /* * IP-over-InfiniBand, as specified by RFC 4391. * * Requested by Petr Sumbera . */ #define DLT_IPOIB 242 /* * MPEG-2 transport stream (ISO 13818-1/ITU-T H.222.0). * * Requested by Guy Martin . */ #define DLT_MPEG_2_TS 243 /* * ng4T GmbH's UMTS Iub/Iur-over-ATM and Iub/Iur-over-IP format as * used by their ng40 protocol tester. * * Requested by Jens Grimmer . */ #define DLT_NG40 244 /* * Pseudo-header giving adapter number and flags, followed by an NFC * (Near-Field Communications) Logical Link Control Protocol (LLCP) PDU, * as specified by NFC Forum Logical Link Control Protocol Technical * Specification LLCP 1.1. * * Requested by Mike Wakerly . */ #define DLT_NFC_LLCP 245 /* * 246 is used as LINKTYPE_PFSYNC; do not use it for any other purpose. * * DLT_PFSYNC has different values on different platforms, and all of * them collide with something used elsewhere. On platforms that * don't already define it, define it as 246. */ #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) && !defined(__APPLE__) #define DLT_PFSYNC 246 #endif /* * Raw InfiniBand packets, starting with the Local Routing Header. * * Requested by Oren Kladnitsky . */ #define DLT_INFINIBAND 247 /* * SCTP, with no lower-level protocols (i.e., no IPv4 or IPv6). * * Requested by Michael Tuexen . */ #define DLT_SCTP 248 /* * USB packets, beginning with a USBPcap header. * * Requested by Tomasz Mon */ #define DLT_USBPCAP 249 /* * Schweitzer Engineering Laboratories "RTAC" product serial-line * packets. * * Requested by Chris Bontje . */ #define DLT_RTAC_SERIAL 250 /* * Bluetooth Low Energy air interface link-layer packets. * * Requested by Mike Kershaw . */ #define DLT_BLUETOOTH_LE_LL 251 /* * DLT type for upper-protocol layer PDU saves from wireshark. * * the actual contents are determined by two TAGs stored with each * packet: * EXP_PDU_TAG_LINKTYPE the link type (LINKTYPE_ value) of the * original packet. * * EXP_PDU_TAG_PROTO_NAME the name of the wireshark dissector * that can make sense of the data stored. */ #define DLT_WIRESHARK_UPPER_PDU 252 /* * DLT type for the netlink protocol (nlmon devices). */ #define DLT_NETLINK 253 /* * Bluetooth Linux Monitor headers for the BlueZ stack. */ #define DLT_BLUETOOTH_LINUX_MONITOR 254 /* * Bluetooth Basic Rate/Enhanced Data Rate baseband packets, as * captured by Ubertooth. */ #define DLT_BLUETOOTH_BREDR_BB 255 /* * Bluetooth Low Energy link layer packets, as captured by Ubertooth. */ #define DLT_BLUETOOTH_LE_LL_WITH_PHDR 256 /* * PROFIBUS data link layer. */ #define DLT_PROFIBUS_DL 257 /* * Apple's DLT_PKTAP headers. * * Sadly, the folks at Apple either had no clue that the DLT_USERn values * are for internal use within an organization and partners only, and * didn't know that the right way to get a link-layer header type is to * ask tcpdump.org for one, or knew and didn't care, so they just * used DLT_USER2, which causes problems for everything except for * their version of tcpdump. * * So I'll just give them one; hopefully this will show up in a * libpcap release in time for them to get this into 10.10 Big Sur * or whatever Mavericks' successor is called. LINKTYPE_PKTAP * will be 258 *even on OS X*; that is *intentional*, so that * PKTAP files look the same on *all* OSes (different OSes can have * different numerical values for a given DLT_, but *MUST NOT* have * different values for what goes in a file, as files can be moved * between OSes!). * * When capturing, on a system with a Darwin-based OS, on a device * that returns 149 (DLT_USER2 and Apple's DLT_PKTAP) with this * version of libpcap, the DLT_ value for the pcap_t will be DLT_PKTAP, * and that will continue to be DLT_USER2 on Darwin-based OSes. That way, * binary compatibility with Mavericks is preserved for programs using * this version of libpcap. This does mean that if you were using * DLT_USER2 for some capture device on OS X, you can't do so with * this version of libpcap, just as you can't with Apple's libpcap - * on OS X, they define DLT_PKTAP to be DLT_USER2, so programs won't * be able to distinguish between PKTAP and whatever you were using * DLT_USER2 for. * * If the program saves the capture to a file using this version of * libpcap's pcap_dump code, the LINKTYPE_ value in the file will be * LINKTYPE_PKTAP, which will be 258, even on Darwin-based OSes. * That way, the file will *not* be a DLT_USER2 file. That means * that the latest version of tcpdump, when built with this version * of libpcap, and sufficiently recent versions of Wireshark will * be able to read those files and interpret them correctly; however, * Apple's version of tcpdump in OS X 10.9 won't be able to handle * them. (Hopefully, Apple will pick up this version of libpcap, * and the corresponding version of tcpdump, so that tcpdump will * be able to handle the old LINKTYPE_USER2 captures *and* the new * LINKTYPE_PKTAP captures.) */ #ifdef __APPLE__ #define DLT_PKTAP DLT_USER2 #else #define DLT_PKTAP 258 #endif /* * Ethernet packets preceded by a header giving the last 6 octets * of the preamble specified by 802.3-2012 Clause 65, section * 65.1.3.2 "Transmit". */ #define DLT_EPON 259 /* * IPMI trace packets, as specified by Table 3-20 "Trace Data Block Format" * in the PICMG HPM.2 specification. */ #define DLT_IPMI_HPM_2 260 /* * per Joshua Wright , formats for Zwave captures. */ #define DLT_ZWAVE_R1_R2 261 #define DLT_ZWAVE_R3 262 /* * per Steve Karg , formats for Wattstopper * Digital Lighting Management room bus serial protocol captures. */ #define DLT_WATTSTOPPER_DLM 263 /* * ISO 14443 contactless smart card messages. */ #define DLT_ISO_14443 264 /* * Radio data system (RDS) groups. IEC 62106. * Per Jonathan Brucker . */ #define DLT_RDS 265 /* * In case the code that includes this file (directly or indirectly) * has also included OS files that happen to define DLT_MATCHING_MAX, * with a different value (perhaps because that OS hasn't picked up * the latest version of our DLT definitions), we undefine the * previous value of DLT_MATCHING_MAX. */ #ifdef DLT_MATCHING_MAX #undef DLT_MATCHING_MAX #endif #define DLT_MATCHING_MAX 265 /* highest value in the "matching" range */ /* * DLT and savefile link type values are split into a class and * a member of that class. A class value of 0 indicates a regular * DLT_/LINKTYPE_ value. */ #define DLT_CLASS(x) ((x) & 0x03ff0000) /* * NetBSD-specific generic "raw" link type. The class value indicates * that this is the generic raw type, and the lower 16 bits are the * address family we're dealing with. Those values are NetBSD-specific; * do not assume that they correspond to AF_ values for your operating * system. */ #define DLT_CLASS_NETBSD_RAWAF 0x02240000 #define DLT_NETBSD_RAWAF(af) (DLT_CLASS_NETBSD_RAWAF | (af)) #define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff) #define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF) #endif /* !defined(lib_pcap_dlt_h) */ libpcap-1.8.1/pcap/pcap.h0000644000026300017510000005102513003771737013310 0ustar mcrmcr/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ /* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lib_pcap_pcap_h #define lib_pcap_pcap_h #include #if defined(_WIN32) #include #elif defined(MSDOS) #include #include /* u_int, u_char etc. */ #else /* UN*X */ #include #include #endif /* _WIN32/MSDOS/UN*X */ #ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H #include #endif #include #ifdef __cplusplus extern "C" { #endif /* * Version number of the current version of the pcap file format. * * NOTE: this is *NOT* the version number of the libpcap library. * To fetch the version information for the version of libpcap * you're using, use pcap_lib_version(). */ #define PCAP_VERSION_MAJOR 2 #define PCAP_VERSION_MINOR 4 #define PCAP_ERRBUF_SIZE 256 /* * Compatibility for systems that have a bpf.h that * predates the bpf typedefs for 64-bit support. */ #if BPF_RELEASE - 0 < 199406 typedef int bpf_int32; typedef u_int bpf_u_int32; #endif typedef struct pcap pcap_t; typedef struct pcap_dumper pcap_dumper_t; typedef struct pcap_if pcap_if_t; typedef struct pcap_addr pcap_addr_t; /* * The first record in the file contains saved values for some * of the flags used in the printout phases of tcpdump. * Many fields here are 32 bit ints so compilers won't insert unwanted * padding; these files need to be interchangeable across architectures. * * Do not change the layout of this structure, in any way (this includes * changes that only affect the length of fields in this structure). * * Also, do not change the interpretation of any of the members of this * structure, in any way (this includes using values other than * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" * field). * * Instead: * * introduce a new structure for the new format, if the layout * of the structure changed; * * send mail to "tcpdump-workers@lists.tcpdump.org", requesting * a new magic number for your new capture file format, and, when * you get the new magic number, put it in "savefile.c"; * * use that magic number for save files with the changed file * header; * * make the code in "savefile.c" capable of reading files with * the old file header as well as files with the new file header * (using the magic number to determine the header format). * * Then supply the changes by forking the branch at * * https://github.com/the-tcpdump-group/libpcap/issues * * and issuing a pull request, so that future versions of libpcap and * programs that use it (such as tcpdump) will be able to read your new * capture file format. */ struct pcap_file_header { bpf_u_int32 magic; u_short version_major; u_short version_minor; bpf_int32 thiszone; /* gmt to local correction */ bpf_u_int32 sigfigs; /* accuracy of timestamps */ bpf_u_int32 snaplen; /* max length saved portion of each pkt */ bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ }; /* * Macros for the value returned by pcap_datalink_ext(). * * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro * gives the FCS length of packets in the capture. */ #define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000) #define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28) #define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000) typedef enum { PCAP_D_INOUT = 0, PCAP_D_IN, PCAP_D_OUT } pcap_direction_t; /* * Generic per-packet information, as supplied by libpcap. * * The time stamp can and should be a "struct timeval", regardless of * whether your system supports 32-bit tv_sec in "struct timeval", * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit * and 64-bit applications. The on-disk format of savefiles uses 32-bit * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit * and 64-bit versions of libpcap, even if they're on the same platform, * should supply the appropriate version of "struct timeval", even if * that's not what the underlying packet capture mechanism supplies. */ struct pcap_pkthdr { struct timeval ts; /* time stamp */ bpf_u_int32 caplen; /* length of portion present */ bpf_u_int32 len; /* length this packet (off wire) */ }; /* * As returned by the pcap_stats() */ struct pcap_stat { u_int ps_recv; /* number of packets received */ u_int ps_drop; /* number of packets dropped */ u_int ps_ifdrop; /* drops by interface -- only supported on some platforms */ #if defined(_WIN32) && defined(HAVE_REMOTE) u_int ps_capt; /* number of packets that reach the application */ u_int ps_sent; /* number of packets sent by the server on the network */ u_int ps_netdrop; /* number of packets lost on the network */ #endif /* _WIN32 && HAVE_REMOTE */ }; #ifdef MSDOS /* * As returned by the pcap_stats_ex() */ struct pcap_stat_ex { u_long rx_packets; /* total packets received */ u_long tx_packets; /* total packets transmitted */ u_long rx_bytes; /* total bytes received */ u_long tx_bytes; /* total bytes transmitted */ u_long rx_errors; /* bad packets received */ u_long tx_errors; /* packet transmit problems */ u_long rx_dropped; /* no space in Rx buffers */ u_long tx_dropped; /* no space available for Tx */ u_long multicast; /* multicast packets received */ u_long collisions; /* detailed rx_errors: */ u_long rx_length_errors; u_long rx_over_errors; /* receiver ring buff overflow */ u_long rx_crc_errors; /* recv'd pkt with crc error */ u_long rx_frame_errors; /* recv'd frame alignment error */ u_long rx_fifo_errors; /* recv'r fifo overrun */ u_long rx_missed_errors; /* recv'r missed packet */ /* detailed tx_errors */ u_long tx_aborted_errors; u_long tx_carrier_errors; u_long tx_fifo_errors; u_long tx_heartbeat_errors; u_long tx_window_errors; }; #endif /* * Item in a list of interfaces. */ struct pcap_if { struct pcap_if *next; char *name; /* name to hand to "pcap_open_live()" */ char *description; /* textual description of interface, or NULL */ struct pcap_addr *addresses; bpf_u_int32 flags; /* PCAP_IF_ interface flags */ }; #define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ #define PCAP_IF_UP 0x00000002 /* interface is up */ #define PCAP_IF_RUNNING 0x00000004 /* interface is running */ /* * Representation of an interface address. */ struct pcap_addr { struct pcap_addr *next; struct sockaddr *addr; /* address */ struct sockaddr *netmask; /* netmask for that address */ struct sockaddr *broadaddr; /* broadcast address for that address */ struct sockaddr *dstaddr; /* P2P destination address for that address */ }; typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *); /* * Error codes for the pcap API. * These will all be negative, so you can check for the success or * failure of a call that returns these codes by checking for a * negative value. */ #define PCAP_ERROR -1 /* generic error code */ #define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */ #define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */ #define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */ #define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */ #define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */ #define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */ #define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */ #define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */ #define PCAP_ERROR_CANTSET_TSTAMP_TYPE -10 /* this device doesn't support setting the time stamp type */ #define PCAP_ERROR_PROMISC_PERM_DENIED -11 /* you don't have permission to capture in promiscuous mode */ #define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12 /* the requested time stamp precision is not supported */ /* * Warning codes for the pcap API. * These will all be positive and non-zero, so they won't look like * errors. */ #define PCAP_WARNING 1 /* generic warning code */ #define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */ #define PCAP_WARNING_TSTAMP_TYPE_NOTSUP 3 /* the requested time stamp type is not supported */ /* * Value to pass to pcap_compile() as the netmask if you don't know what * the netmask is. */ #define PCAP_NETMASK_UNKNOWN 0xffffffff PCAP_API char *pcap_lookupdev(char *); PCAP_API int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); PCAP_API pcap_t *pcap_create(const char *, char *); PCAP_API int pcap_set_snaplen(pcap_t *, int); PCAP_API int pcap_set_promisc(pcap_t *, int); PCAP_API int pcap_can_set_rfmon(pcap_t *); PCAP_API int pcap_set_rfmon(pcap_t *, int); PCAP_API int pcap_set_timeout(pcap_t *, int); PCAP_API int pcap_set_tstamp_type(pcap_t *, int); PCAP_API int pcap_set_immediate_mode(pcap_t *, int); PCAP_API int pcap_set_buffer_size(pcap_t *, int); PCAP_API int pcap_set_tstamp_precision(pcap_t *, int); PCAP_API int pcap_get_tstamp_precision(pcap_t *); PCAP_API int pcap_activate(pcap_t *); PCAP_API int pcap_list_tstamp_types(pcap_t *, int **); PCAP_API void pcap_free_tstamp_types(int *); PCAP_API int pcap_tstamp_type_name_to_val(const char *); PCAP_API const char *pcap_tstamp_type_val_to_name(int); PCAP_API const char *pcap_tstamp_type_val_to_description(int); /* * Time stamp types. * Not all systems and interfaces will necessarily support all of these. * * A system that supports PCAP_TSTAMP_HOST is offering time stamps * provided by the host machine, rather than by the capture device, * but not committing to any characteristics of the time stamp; * it will not offer any of the PCAP_TSTAMP_HOST_ subtypes. * * PCAP_TSTAMP_HOST_LOWPREC is a time stamp, provided by the host machine, * that's low-precision but relatively cheap to fetch; it's normally done * using the system clock, so it's normally synchronized with times you'd * fetch from system calls. * * PCAP_TSTAMP_HOST_HIPREC is a time stamp, provided by the host machine, * that's high-precision; it might be more expensive to fetch. It might * or might not be synchronized with the system clock, and might have * problems with time stamps for packets received on different CPUs, * depending on the platform. * * PCAP_TSTAMP_ADAPTER is a high-precision time stamp supplied by the * capture device; it's synchronized with the system clock. * * PCAP_TSTAMP_ADAPTER_UNSYNCED is a high-precision time stamp supplied by * the capture device; it's not synchronized with the system clock. * * Note that time stamps synchronized with the system clock can go * backwards, as the system clock can go backwards. If a clock is * not in sync with the system clock, that could be because the * system clock isn't keeping accurate time, because the other * clock isn't keeping accurate time, or both. * * Note that host-provided time stamps generally correspond to the * time when the time-stamping code sees the packet; this could * be some unknown amount of time after the first or last bit of * the packet is received by the network adapter, due to batching * of interrupts for packet arrival, queueing delays, etc.. */ #define PCAP_TSTAMP_HOST 0 /* host-provided, unknown characteristics */ #define PCAP_TSTAMP_HOST_LOWPREC 1 /* host-provided, low precision */ #define PCAP_TSTAMP_HOST_HIPREC 2 /* host-provided, high precision */ #define PCAP_TSTAMP_ADAPTER 3 /* device-provided, synced with the system clock */ #define PCAP_TSTAMP_ADAPTER_UNSYNCED 4 /* device-provided, not synced with the system clock */ /* * Time stamp resolution types. * Not all systems and interfaces will necessarily support all of these * resolutions when doing live captures; all of them can be requested * when reading a savefile. */ #define PCAP_TSTAMP_PRECISION_MICRO 0 /* use timestamps with microsecond precision, default */ #define PCAP_TSTAMP_PRECISION_NANO 1 /* use timestamps with nanosecond precision */ PCAP_API pcap_t *pcap_open_live(const char *, int, int, int, char *); PCAP_API pcap_t *pcap_open_dead(int, int); PCAP_API pcap_t *pcap_open_dead_with_tstamp_precision(int, int, u_int); PCAP_API pcap_t *pcap_open_offline_with_tstamp_precision(const char *, u_int, char *); PCAP_API pcap_t *pcap_open_offline(const char *, char *); #ifdef _WIN32 PCAP_API pcap_t *pcap_hopen_offline_with_tstamp_precision(intptr_t, u_int, char *); PCAP_API pcap_t *pcap_hopen_offline(intptr_t, char *); /* * If we're building libpcap, these are internal routines in savefile.c, * so we mustn't define them as macros. */ #ifndef BUILDING_PCAP #define pcap_fopen_offline_with_tstamp_precision(f,p,b) \ pcap_hopen_offline_with_tstamp_precision(_get_osfhandle(_fileno(f)), p, b) #define pcap_fopen_offline(f,b) \ pcap_hopen_offline(_get_osfhandle(_fileno(f)), b) #endif #else /*_WIN32*/ PCAP_API pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *); PCAP_API pcap_t *pcap_fopen_offline(FILE *, char *); #endif /*_WIN32*/ PCAP_API void pcap_close(pcap_t *); PCAP_API int pcap_loop(pcap_t *, int, pcap_handler, u_char *); PCAP_API int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); PCAP_API const u_char *pcap_next(pcap_t *, struct pcap_pkthdr *); PCAP_API int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); PCAP_API void pcap_breakloop(pcap_t *); PCAP_API int pcap_stats(pcap_t *, struct pcap_stat *); PCAP_API int pcap_setfilter(pcap_t *, struct bpf_program *); PCAP_API int pcap_setdirection(pcap_t *, pcap_direction_t); PCAP_API int pcap_getnonblock(pcap_t *, char *); PCAP_API int pcap_setnonblock(pcap_t *, int, char *); PCAP_API int pcap_inject(pcap_t *, const void *, size_t); PCAP_API int pcap_sendpacket(pcap_t *, const u_char *, int); PCAP_API const char *pcap_statustostr(int); PCAP_API const char *pcap_strerror(int); PCAP_API char *pcap_geterr(pcap_t *); PCAP_API void pcap_perror(pcap_t *, const char *); PCAP_API int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, bpf_u_int32); PCAP_API int pcap_compile_nopcap(int, int, struct bpf_program *, const char *, int, bpf_u_int32); PCAP_API void pcap_freecode(struct bpf_program *); PCAP_API int pcap_offline_filter(const struct bpf_program *, const struct pcap_pkthdr *, const u_char *); PCAP_API int pcap_datalink(pcap_t *); PCAP_API int pcap_datalink_ext(pcap_t *); PCAP_API int pcap_list_datalinks(pcap_t *, int **); PCAP_API int pcap_set_datalink(pcap_t *, int); PCAP_API void pcap_free_datalinks(int *); PCAP_API int pcap_datalink_name_to_val(const char *); PCAP_API const char *pcap_datalink_val_to_name(int); PCAP_API const char *pcap_datalink_val_to_description(int); PCAP_API int pcap_snapshot(pcap_t *); PCAP_API int pcap_is_swapped(pcap_t *); PCAP_API int pcap_major_version(pcap_t *); PCAP_API int pcap_minor_version(pcap_t *); /* XXX */ PCAP_API FILE *pcap_file(pcap_t *); PCAP_API int pcap_fileno(pcap_t *); #ifdef _WIN32 PCAP_API int pcap_wsockinit(void); #endif PCAP_API pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); PCAP_API pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); PCAP_API pcap_dumper_t *pcap_dump_open_append(pcap_t *, const char *); PCAP_API FILE *pcap_dump_file(pcap_dumper_t *); PCAP_API long pcap_dump_ftell(pcap_dumper_t *); PCAP_API int pcap_dump_flush(pcap_dumper_t *); PCAP_API void pcap_dump_close(pcap_dumper_t *); PCAP_API void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); PCAP_API int pcap_findalldevs(pcap_if_t **, char *); PCAP_API void pcap_freealldevs(pcap_if_t *); PCAP_API const char *pcap_lib_version(void); /* * On at least some versions of NetBSD and QNX, we don't want to declare * bpf_filter() here, as it's also be declared in , with a * different signature, but, on other BSD-flavored UN*Xes, it's not * declared in , so we *do* want to declare it here, so it's * declared when we build pcap-bpf.c. */ #if !defined(__NetBSD__) && !defined(__QNX__) PCAP_API u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); #endif PCAP_API int bpf_validate(const struct bpf_insn *f, int len); PCAP_API char *bpf_image(const struct bpf_insn *, int); PCAP_API void bpf_dump(const struct bpf_program *, int); #if defined(_WIN32) /* * Win32 definitions */ /*! \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit(). */ struct pcap_send_queue { u_int maxlen; /* Maximum size of the the queue, in bytes. This variable contains the size of the buffer field. */ u_int len; /* Current size of the queue, in bytes. */ char *buffer; /* Buffer containing the packets to be sent. */ }; typedef struct pcap_send_queue pcap_send_queue; /*! \brief This typedef is a support for the pcap_get_airpcap_handle() function */ #if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) #define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ typedef struct _AirpcapHandle *PAirpcapHandle; #endif PCAP_API int pcap_setbuff(pcap_t *p, int dim); PCAP_API int pcap_setmode(pcap_t *p, int mode); PCAP_API int pcap_setmintocopy(pcap_t *p, int size); PCAP_API HANDLE pcap_getevent(pcap_t *p); PCAP_API int pcap_oid_get_request(pcap_t *, bpf_u_int32, void *, size_t *); PCAP_API int pcap_oid_set_request(pcap_t *, bpf_u_int32, const void *, size_t *); PCAP_API pcap_send_queue* pcap_sendqueue_alloc(u_int memsize); PCAP_API void pcap_sendqueue_destroy(pcap_send_queue* queue); PCAP_API int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); PCAP_API u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync); PCAP_API struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size); PCAP_API int pcap_setuserbuffer(pcap_t *p, int size); PCAP_API int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks); PCAP_API int pcap_live_dump_ended(pcap_t *p, int sync); PCAP_API int pcap_start_oem(char* err_str, int flags); PCAP_API PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p); #define MODE_CAPT 0 #define MODE_STAT 1 #define MODE_MON 2 #elif defined(MSDOS) /* * MS-DOS definitions */ PCAP_API int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); PCAP_API void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); PCAP_API u_long pcap_mac_packets (void); #else /* UN*X */ /* * UN*X definitions */ PCAP_API int pcap_get_selectable_fd(pcap_t *); #endif /* _WIN32/MSDOS/UN*X */ #ifdef HAVE_REMOTE /* Includes most of the public stuff that is needed for the remote capture */ #include #endif /* HAVE_REMOTE */ #ifdef __cplusplus } #endif #endif /* lib_pcap_pcap_h */ libpcap-1.8.1/pcap/vlan.h0000644000026300017510000000401313003771737013320 0ustar mcrmcr/*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lib_pcap_vlan_h #define lib_pcap_vlan_h struct vlan_tag { u_int16_t vlan_tpid; /* ETH_P_8021Q */ u_int16_t vlan_tci; /* VLAN TCI */ }; #define VLAN_TAG_LEN 4 #endif libpcap-1.8.1/pcap/bluetooth.h0000644000026300017510000000414313003771737014371 0ustar mcrmcr/* * Copyright (c) 2006 Paolo Abeni (Italy) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * bluetooth data struct * By Paolo Abeni */ #ifndef lib_pcap_bluetooth_h #define lib_pcap_bluetooth_h /* * Header prepended libpcap to each bluetooth h4 frame, * fields are in network byte order */ typedef struct _pcap_bluetooth_h4_header { u_int32_t direction; /* if first bit is set direction is incoming */ } pcap_bluetooth_h4_header; /* * Header prepended libpcap to each bluetooth linux monitor frame, * fields are in network byte order */ typedef struct _pcap_bluetooth_linux_monitor_header { u_int16_t adapter_id; u_int16_t opcode; } pcap_bluetooth_linux_monitor_header; #endif libpcap-1.8.1/pcap/usb.h0000644000026300017510000001070613003771737013157 0ustar mcrmcr/* * Copyright (c) 2006 Paolo Abeni (Italy) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Basic USB data struct * By Paolo Abeni */ #ifndef lib_pcap_usb_h #define lib_pcap_usb_h /* * possible transfer mode */ #define URB_TRANSFER_IN 0x80 #define URB_ISOCHRONOUS 0x0 #define URB_INTERRUPT 0x1 #define URB_CONTROL 0x2 #define URB_BULK 0x3 /* * possible event type */ #define URB_SUBMIT 'S' #define URB_COMPLETE 'C' #define URB_ERROR 'E' /* * USB setup header as defined in USB specification. * Appears at the front of each Control S-type packet in DLT_USB captures. */ typedef struct _usb_setup { u_int8_t bmRequestType; u_int8_t bRequest; u_int16_t wValue; u_int16_t wIndex; u_int16_t wLength; } pcap_usb_setup; /* * Information from the URB for Isochronous transfers. */ typedef struct _iso_rec { int32_t error_count; int32_t numdesc; } iso_rec; /* * Header prepended by linux kernel to each event. * Appears at the front of each packet in DLT_USB_LINUX captures. */ typedef struct _usb_header { u_int64_t id; u_int8_t event_type; u_int8_t transfer_type; u_int8_t endpoint_number; u_int8_t device_address; u_int16_t bus_id; char setup_flag;/*if !=0 the urb setup header is not present*/ char data_flag; /*if !=0 no urb data is present*/ int64_t ts_sec; int32_t ts_usec; int32_t status; u_int32_t urb_len; u_int32_t data_len; /* amount of urb data really present in this event*/ pcap_usb_setup setup; } pcap_usb_header; /* * Header prepended by linux kernel to each event for the 2.6.31 * and later kernels; for the 2.6.21 through 2.6.30 kernels, the * "iso_rec" information, and the fields starting with "interval" * are zeroed-out padding fields. * * Appears at the front of each packet in DLT_USB_LINUX_MMAPPED captures. */ typedef struct _usb_header_mmapped { u_int64_t id; u_int8_t event_type; u_int8_t transfer_type; u_int8_t endpoint_number; u_int8_t device_address; u_int16_t bus_id; char setup_flag;/*if !=0 the urb setup header is not present*/ char data_flag; /*if !=0 no urb data is present*/ int64_t ts_sec; int32_t ts_usec; int32_t status; u_int32_t urb_len; u_int32_t data_len; /* amount of urb data really present in this event*/ union { pcap_usb_setup setup; iso_rec iso; } s; int32_t interval; /* for Interrupt and Isochronous events */ int32_t start_frame; /* for Isochronous events */ u_int32_t xfer_flags; /* copy of URB's transfer flags */ u_int32_t ndesc; /* number of isochronous descriptors */ } pcap_usb_header_mmapped; /* * Isochronous descriptors; for isochronous transfers there might be * one or more of these at the beginning of the packet data. The * number of descriptors is given by the "ndesc" field in the header; * as indicated, in older kernels that don't put the descriptors at * the beginning of the packet, that field is zeroed out, so that field * can be trusted even in captures from older kernels. */ typedef struct _usb_isodesc { int32_t status; u_int32_t offset; u_int32_t len; u_int8_t pad[4]; } usb_isodesc; #endif libpcap-1.8.1/pcap/nflog.h0000644000026300017510000000764313003771737013501 0ustar mcrmcr/* * Copyright (c) 2013, Petar Alilovic, * Faculty of Electrical Engineering and Computing, University of Zagreb * All rights reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef lib_pcap_nflog_h #define lib_pcap_nflog_h /* * Structure of an NFLOG header and TLV parts, as described at * http://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html * * The NFLOG header is big-endian. * * The TLV length and type are in host byte order. The value is either * big-endian or is an array of bytes in some externally-specified byte * order (text string, link-layer address, link-layer header, packet * data, etc.). */ typedef struct nflog_hdr { u_int8_t nflog_family; /* address family */ u_int8_t nflog_version; /* version */ u_int16_t nflog_rid; /* resource ID */ } nflog_hdr_t; typedef struct nflog_tlv { u_int16_t tlv_length; /* tlv length */ u_int16_t tlv_type; /* tlv type */ /* value follows this */ } nflog_tlv_t; typedef struct nflog_packet_hdr { u_int16_t hw_protocol; /* hw protocol */ u_int8_t hook; /* netfilter hook */ u_int8_t pad; /* padding to 32 bits */ } nflog_packet_hdr_t; typedef struct nflog_hwaddr { u_int16_t hw_addrlen; /* address length */ u_int16_t pad; /* padding to 32-bit boundary */ u_int8_t hw_addr[8]; /* address, up to 8 bytes */ } nflog_hwaddr_t; typedef struct nflog_timestamp { u_int64_t sec; u_int64_t usec; } nflog_timestamp_t; /* * TLV types. */ #define NFULA_PACKET_HDR 1 /* nflog_packet_hdr_t */ #define NFULA_MARK 2 /* packet mark from skbuff */ #define NFULA_TIMESTAMP 3 /* nflog_timestamp_t for skbuff's time stamp */ #define NFULA_IFINDEX_INDEV 4 /* ifindex of device on which packet received (possibly bridge group) */ #define NFULA_IFINDEX_OUTDEV 5 /* ifindex of device on which packet transmitted (possibly bridge group) */ #define NFULA_IFINDEX_PHYSINDEV 6 /* ifindex of physical device on which packet received (not bridge group) */ #define NFULA_IFINDEX_PHYSOUTDEV 7 /* ifindex of physical device on which packet transmitted (not bridge group) */ #define NFULA_HWADDR 8 /* nflog_hwaddr_t for hardware address */ #define NFULA_PAYLOAD 9 /* packet payload */ #define NFULA_PREFIX 10 /* text string - null-terminated, count includes NUL */ #define NFULA_UID 11 /* UID owning socket on which packet was sent/received */ #define NFULA_SEQ 12 /* sequence number of packets on this NFLOG socket */ #define NFULA_SEQ_GLOBAL 13 /* sequence number of pakets on all NFLOG sockets */ #define NFULA_GID 14 /* GID owning socket on which packet was sent/received */ #define NFULA_HWTYPE 15 /* ARPHRD_ type of skbuff's device */ #define NFULA_HWHEADER 16 /* skbuff's MAC-layer header */ #define NFULA_HWLEN 17 /* length of skbuff's MAC-layer header */ #endif libpcap-1.8.1/pcap/sll.h0000644000026300017510000001277613003771737013171 0ustar mcrmcr/*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * For captures on Linux cooked sockets, we construct a fake header * that includes: * * a 2-byte "packet type" which is one of: * * LINUX_SLL_HOST packet was sent to us * LINUX_SLL_BROADCAST packet was broadcast * LINUX_SLL_MULTICAST packet was multicast * LINUX_SLL_OTHERHOST packet was sent to somebody else * LINUX_SLL_OUTGOING packet was sent *by* us; * * a 2-byte Ethernet protocol field; * * a 2-byte link-layer type; * * a 2-byte link-layer address length; * * an 8-byte source link-layer address, whose actual length is * specified by the previous value. * * All fields except for the link-layer address are in network byte order. * * DO NOT change the layout of this structure, or change any of the * LINUX_SLL_ values below. If you must change the link-layer header * for a "cooked" Linux capture, introduce a new DLT_ type (ask * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it * a value that collides with a value already being used), and use the * new header in captures of that type, so that programs that can * handle DLT_LINUX_SLL captures will continue to handle them correctly * without any change, and so that capture files with different headers * can be told apart and programs that read them can dissect the * packets in them. */ #ifndef lib_pcap_sll_h #define lib_pcap_sll_h /* * A DLT_LINUX_SLL fake link-layer header. */ #define SLL_HDR_LEN 16 /* total header length */ #define SLL_ADDRLEN 8 /* length of address field */ struct sll_header { u_int16_t sll_pkttype; /* packet type */ u_int16_t sll_hatype; /* link-layer address type */ u_int16_t sll_halen; /* link-layer address length */ u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ u_int16_t sll_protocol; /* protocol */ }; /* * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the * PACKET_ values on Linux, but are defined here so that they're * available even on systems other than Linux, and so that they * don't change even if the PACKET_ values change. */ #define LINUX_SLL_HOST 0 #define LINUX_SLL_BROADCAST 1 #define LINUX_SLL_MULTICAST 2 #define LINUX_SLL_OTHERHOST 3 #define LINUX_SLL_OUTGOING 4 /* * The LINUX_SLL_ values for "sll_protocol"; these correspond to the * ETH_P_ values on Linux, but are defined here so that they're * available even on systems other than Linux. We assume, for now, * that the ETH_P_ values won't change in Linux; if they do, then: * * if we don't translate them in "pcap-linux.c", capture files * won't necessarily be readable if captured on a system that * defines ETH_P_ values that don't match these values; * * if we do translate them in "pcap-linux.c", that makes life * unpleasant for the BPF code generator, as the values you test * for in the kernel aren't the values that you test for when * reading a capture file, so the fixup code run on BPF programs * handed to the kernel ends up having to do more work. * * Add other values here as necessary, for handling packet types that * might show up on non-Ethernet, non-802.x networks. (Not all the ones * in the Linux "if_ether.h" will, I suspect, actually show up in * captures.) */ #define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ #define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ #define LINUX_SLL_P_CAN 0x000C /* CAN frames, with SocketCAN pseudo-headers */ #define LINUX_SLL_P_CANFD 0x000D /* CAN FD frames, with SocketCAN pseudo-headers */ #endif libpcap-1.8.1/pcap/bpf.h0000644000026300017510000002071513003771737013136 0ustar mcrmcr/*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)bpf.h 7.1 (Berkeley) 5/7/91 */ /* * This is libpcap's cut-down version of bpf.h; it includes only * the stuff needed for the code generator and the userland BPF * interpreter, and the libpcap APIs for setting filters, etc.. * * "pcap-bpf.c" will include the native OS version, as it deals with * the OS's BPF implementation. * * At least two programs found by Google Code Search explicitly includes * (even though / includes it for you), * so moving that stuff to would break the build for some * programs. */ /* * If we've already included , don't re-define this stuff. * We assume BSD-style multiple-include protection in , * which is true of all but the oldest versions of FreeBSD and NetBSD, * or Tru64 UNIX-style multiple-include protection (or, at least, * Tru64 UNIX 5.x-style; I don't have earlier versions available to check), * or AIX-style multiple-include protection (or, at least, AIX 5.x-style; * I don't have earlier versions available to check), or QNX-style * multiple-include protection (as per GitHub pull request #394). * * We do not check for BPF_MAJOR_VERSION, as that's defined by * , which is directly or indirectly included in some * programs that also include pcap.h, and doesn't * define stuff we need. * * This also provides our own multiple-include protection. */ #if !defined(_NET_BPF_H_) && !defined(_NET_BPF_H_INCLUDED) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) #define lib_pcap_bpf_h #include #ifdef __cplusplus extern "C" { #endif /* BSD style release date */ #define BPF_RELEASE 199606 #ifdef MSDOS /* must be 32-bit */ typedef long bpf_int32; typedef unsigned long bpf_u_int32; #else typedef int bpf_int32; typedef u_int bpf_u_int32; #endif /* * Alignment macros. BPF_WORDALIGN rounds up to the next * even multiple of BPF_ALIGNMENT. * * Tcpdump's print-pflog.c uses this, so we define it here. */ #ifndef __NetBSD__ #define BPF_ALIGNMENT sizeof(bpf_int32) #else #define BPF_ALIGNMENT sizeof(long) #endif #define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) /* * Structure for "pcap_compile()", "pcap_setfilter()", etc.. */ struct bpf_program { u_int bf_len; struct bpf_insn *bf_insns; }; #include /* * The instruction encodings. * * Please inform tcpdump-workers@lists.tcpdump.org if you use any * of the reserved values, so that we can note that they're used * (and perhaps implement it in the reference BPF implementation * and encourage its implementation elsewhere). */ /* * The upper 8 bits of the opcode aren't used. BSD/OS used 0x8000. */ /* instruction classes */ #define BPF_CLASS(code) ((code) & 0x07) #define BPF_LD 0x00 #define BPF_LDX 0x01 #define BPF_ST 0x02 #define BPF_STX 0x03 #define BPF_ALU 0x04 #define BPF_JMP 0x05 #define BPF_RET 0x06 #define BPF_MISC 0x07 /* ld/ldx fields */ #define BPF_SIZE(code) ((code) & 0x18) #define BPF_W 0x00 #define BPF_H 0x08 #define BPF_B 0x10 /* 0x18 reserved; used by BSD/OS */ #define BPF_MODE(code) ((code) & 0xe0) #define BPF_IMM 0x00 #define BPF_ABS 0x20 #define BPF_IND 0x40 #define BPF_MEM 0x60 #define BPF_LEN 0x80 #define BPF_MSH 0xa0 /* 0xc0 reserved; used by BSD/OS */ /* 0xe0 reserved; used by BSD/OS */ /* alu/jmp fields */ #define BPF_OP(code) ((code) & 0xf0) #define BPF_ADD 0x00 #define BPF_SUB 0x10 #define BPF_MUL 0x20 #define BPF_DIV 0x30 #define BPF_OR 0x40 #define BPF_AND 0x50 #define BPF_LSH 0x60 #define BPF_RSH 0x70 #define BPF_NEG 0x80 #define BPF_MOD 0x90 #define BPF_XOR 0xa0 /* 0xb0 reserved */ /* 0xc0 reserved */ /* 0xd0 reserved */ /* 0xe0 reserved */ /* 0xf0 reserved */ #define BPF_JA 0x00 #define BPF_JEQ 0x10 #define BPF_JGT 0x20 #define BPF_JGE 0x30 #define BPF_JSET 0x40 /* 0x50 reserved; used on BSD/OS */ /* 0x60 reserved */ /* 0x70 reserved */ /* 0x80 reserved */ /* 0x90 reserved */ /* 0xa0 reserved */ /* 0xb0 reserved */ /* 0xc0 reserved */ /* 0xd0 reserved */ /* 0xe0 reserved */ /* 0xf0 reserved */ #define BPF_SRC(code) ((code) & 0x08) #define BPF_K 0x00 #define BPF_X 0x08 /* ret - BPF_K and BPF_X also apply */ #define BPF_RVAL(code) ((code) & 0x18) #define BPF_A 0x10 /* 0x18 reserved */ /* misc */ #define BPF_MISCOP(code) ((code) & 0xf8) #define BPF_TAX 0x00 /* 0x08 reserved */ /* 0x10 reserved */ /* 0x18 reserved */ /* #define BPF_COP 0x20 NetBSD "coprocessor" extensions */ /* 0x28 reserved */ /* 0x30 reserved */ /* 0x38 reserved */ /* #define BPF_COPX 0x40 NetBSD "coprocessor" extensions */ /* also used on BSD/OS */ /* 0x48 reserved */ /* 0x50 reserved */ /* 0x58 reserved */ /* 0x60 reserved */ /* 0x68 reserved */ /* 0x70 reserved */ /* 0x78 reserved */ #define BPF_TXA 0x80 /* 0x88 reserved */ /* 0x90 reserved */ /* 0x98 reserved */ /* 0xa0 reserved */ /* 0xa8 reserved */ /* 0xb0 reserved */ /* 0xb8 reserved */ /* 0xc0 reserved; used on BSD/OS */ /* 0xc8 reserved */ /* 0xd0 reserved */ /* 0xd8 reserved */ /* 0xe0 reserved */ /* 0xe8 reserved */ /* 0xf0 reserved */ /* 0xf8 reserved */ /* * The instruction data structure. */ struct bpf_insn { u_short code; u_char jt; u_char jf; bpf_u_int32 k; }; /* * Auxiliary data, for use when interpreting a filter intended for the * Linux kernel when the kernel rejects the filter (requiring us to * run it in userland). It contains VLAN tag information. */ struct bpf_aux_data { u_short vlan_tag_present; u_short vlan_tag; }; /* * Macros for insn array initializers. */ #define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } #define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } #if __STDC__ || defined(__cplusplus) PCAP_API int bpf_validate(const struct bpf_insn *, int); PCAP_API u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); extern u_int bpf_filter_with_aux_data(const struct bpf_insn *, const u_char *, u_int, u_int, const struct bpf_aux_data *); #else PCAP_API int bpf_validate(); PCAP_API u_int bpf_filter(); extern u_int bpf_filter_with_aux_data(); #endif /* * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). */ #define BPF_MEMWORDS 16 #ifdef __cplusplus } #endif #endif /* !defined(_NET_BPF_H_) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) */ libpcap-1.8.1/pcap/ipnet.h0000644000026300017510000000434013003771737013502 0ustar mcrmcr/*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define IPH_AF_INET 2 /* Matches Solaris's AF_INET */ #define IPH_AF_INET6 26 /* Matches Solaris's AF_INET6 */ #define IPNET_OUTBOUND 1 #define IPNET_INBOUND 2 libpcap-1.8.1/pcap/export-defs.h0000644000026300017510000001013413003771737014621 0ustar mcrmcr/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ /* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lib_pcap_export_defs_h #define lib_pcap_export_defs_h /* * PCAP_API_DEF must be used when defining *data* exported from * libpcap. It can be used when defining *functions* exported * from libpcap, but it doesn't have to be used there. It * should not be used in declarations in headers. * * PCAP_API must be used when *declaring* data or functions * exported from libpcap; PCAP_API_DEF won't work on all platforms. */ /* * Check whether this is GCC major.minor or a later release, or some * compiler that claims to be "just like GCC" of that version or a * later release. */ #define IS_AT_LEAST_GNUC_VERSION(major, minor) \ (defined(__GNUC__) && \ (__GNUC__ > (major) || \ (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))) #if defined(_WIN32) #ifdef BUILDING_PCAP /* * We're compiling libpcap, so we should export functions in our * API. */ #define PCAP_API_DEF __declspec(dllexport) #else #define PCAP_API_DEF __declspec(dllimport) #endif #elif defined(MSDOS) /* XXX - does this need special treatment? */ #define PCAP_API_DEF #else /* UN*X */ #ifdef BUILDING_PCAP /* * We're compiling libpcap, so we should export functions in our API. * The compiler might be configured not to export functions from a * shared library by default, so we might have to explicitly mark * functions as exported. */ #if IS_AT_LEAST_GNUC_VERSION(3, 4) /* * GCC 3.4 or later, or some compiler asserting compatibility with * GCC 3.4 or later, so we have __attribute__((visibility()). */ #define PCAP_API_DEF __attribute__((visibility("default"))) #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) /* * Sun C 5.5 or later, so we have __global. * (Sun C 5.9 and later also have __attribute__((visibility()), * but there's no reason to prefer it with Sun C.) */ #define PCAP_API_DEF __global #else /* * We don't have anything to say. */ #define PCAP_API_DEF #endif #else /* * We're not building libpcap. */ #define PCAP_API_DEF #endif #endif /* _WIN32/MSDOS/UN*X */ #define PCAP_API PCAP_API_DEF extern #endif /* lib_pcap_export_defs_h */ libpcap-1.8.1/fad-getad.c0000644000026300017510000002145313003771737013253 0ustar mcrmcr/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ /* * Copyright (c) 1994, 1995, 1996, 1997, 1998 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include "pcap-int.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif /* * We don't do this on Solaris 11 and later, as it appears there aren't * any AF_PACKET addresses on interfaces, so we don't need this, and * we end up including both the OS's and our , * and their definitions of some data structures collide. */ #if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) # ifdef HAVE_NETPACKET_PACKET_H /* Linux distributions with newer glibc */ # include # else /* HAVE_NETPACKET_PACKET_H */ /* LynxOS, Linux distributions with older glibc */ # ifdef __Lynx__ /* LynxOS */ # include # else /* __Lynx__ */ /* Linux */ # include # include # endif /* __Lynx__ */ # endif /* HAVE_NETPACKET_PACKET_H */ #endif /* (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) */ /* * This is fun. * * In older BSD systems, socket addresses were fixed-length, and * "sizeof (struct sockaddr)" gave the size of the structure. * All addresses fit within a "struct sockaddr". * * In newer BSD systems, the socket address is variable-length, and * there's an "sa_len" field giving the length of the structure; * this allows socket addresses to be longer than 2 bytes of family * and 14 bytes of data. * * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553 * variant of the old BSD scheme (with "struct sockaddr_storage" rather * than "struct sockaddr"), and some use the new BSD scheme. * * Some versions of GNU libc use neither scheme, but has an "SA_LEN()" * macro that determines the size based on the address family. Other * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553 * but not in the final version). On the latter systems, we explicitly * check the AF_ type to determine the length; we assume that on * all those systems we have "struct sockaddr_storage". */ #ifndef SA_LEN #ifdef HAVE_SOCKADDR_SA_LEN #define SA_LEN(addr) ((addr)->sa_len) #else /* HAVE_SOCKADDR_SA_LEN */ #ifdef HAVE_SOCKADDR_STORAGE static size_t get_sa_len(struct sockaddr *addr) { switch (addr->sa_family) { #ifdef AF_INET case AF_INET: return (sizeof (struct sockaddr_in)); #endif #ifdef AF_INET6 case AF_INET6: return (sizeof (struct sockaddr_in6)); #endif #if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) case AF_PACKET: return (sizeof (struct sockaddr_ll)); #endif default: return (sizeof (struct sockaddr)); } } #define SA_LEN(addr) (get_sa_len(addr)) #else /* HAVE_SOCKADDR_STORAGE */ #define SA_LEN(addr) (sizeof (struct sockaddr)) #endif /* HAVE_SOCKADDR_STORAGE */ #endif /* HAVE_SOCKADDR_SA_LEN */ #endif /* SA_LEN */ /* * Get a list of all interfaces that are up and that we can open. * Returns -1 on error, 0 otherwise. * The list, as returned through "alldevsp", may be null if no interfaces * could be opened. */ int pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf, int (*check_usable)(const char *)) { pcap_if_t *devlist = NULL; struct ifaddrs *ifap, *ifa; struct sockaddr *addr, *netmask, *broadaddr, *dstaddr; size_t addr_size, broadaddr_size, dstaddr_size; int ret = 0; char *p, *q; /* * Get the list of interface addresses. * * Note: this won't return information about interfaces * with no addresses, so, if a platform has interfaces * with no interfaces on which traffic can be captured, * we must check for those interfaces as well (see, for * example, what's done on Linux). * * LAN interfaces will probably have link-layer * addresses; I don't know whether all implementations * of "getifaddrs()" now, or in the future, will return * those. */ if (getifaddrs(&ifap) != 0) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "getifaddrs: %s", pcap_strerror(errno)); return (-1); } for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { /* * If this entry has a colon followed by a number at * the end, we assume it's a logical interface. Those * are just the way you assign multiple IP addresses to * a real interface on Linux, so an entry for a logical * interface should be treated like the entry for the * real interface; we do that by stripping off the ":" * and the number. * * XXX - should we do this only on Linux? */ p = strchr(ifa->ifa_name, ':'); if (p != NULL) { /* * We have a ":"; is it followed by a number? */ q = p + 1; while (isdigit((unsigned char)*q)) q++; if (*q == '\0') { /* * All digits after the ":" until the end. * Strip off the ":" and everything after * it. */ *p = '\0'; } } /* * Can we capture on this device? */ if (!(*check_usable)(ifa->ifa_name)) { /* * No. */ continue; } /* * "ifa_addr" was apparently null on at least one * interface on some system. Therefore, we supply * the address and netmask only if "ifa_addr" is * non-null (if there's no address, there's obviously * no netmask). */ if (ifa->ifa_addr != NULL) { addr = ifa->ifa_addr; addr_size = SA_LEN(addr); netmask = ifa->ifa_netmask; } else { addr = NULL; addr_size = 0; netmask = NULL; } /* * Note that, on some platforms, ifa_broadaddr and * ifa_dstaddr could be the same field (true on at * least some versions of *BSD and OS X), so we * can't just check whether the broadcast address * is null and add it if so and check whether the * destination address is null and add it if so. * * Therefore, we must also check the IFF_BROADCAST * flag, and only add a broadcast address if it's * set, and check the IFF_POINTTOPOINT flag, and * only add a destination address if it's set (as * per man page recommendations on some of those * platforms). */ if (ifa->ifa_flags & IFF_BROADCAST && ifa->ifa_broadaddr != NULL) { broadaddr = ifa->ifa_broadaddr; broadaddr_size = SA_LEN(broadaddr); } else { broadaddr = NULL; broadaddr_size = 0; } if (ifa->ifa_flags & IFF_POINTOPOINT && ifa->ifa_dstaddr != NULL) { dstaddr = ifa->ifa_dstaddr; dstaddr_size = SA_LEN(ifa->ifa_dstaddr); } else { dstaddr = NULL; dstaddr_size = 0; } /* * Add information for this address to the list. */ if (add_addr_to_iflist(&devlist, ifa->ifa_name, if_flags_to_pcap_flags(ifa->ifa_name, ifa->ifa_flags), addr, addr_size, netmask, addr_size, broadaddr, broadaddr_size, dstaddr, dstaddr_size, errbuf) < 0) { ret = -1; break; } } freeifaddrs(ifap); if (ret == -1) { /* * We had an error; free the list we've been constructing. */ if (devlist != NULL) { pcap_freealldevs(devlist); devlist = NULL; } } *alldevsp = devlist; return (ret); } libpcap-1.8.1/pcap-linktype.manmisc.in0000644000026300017510000000453613003771737016034 0ustar mcrmcr.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" 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. .\" .TH PCAP-LINKTYPE @MAN_MISC_INFO@ "7 April 2014" .SH NAME pcap-linktype \- link-layer header types supported by libpcap .SH DESCRIPTION For a live capture or ``savefile'', libpcap supplies, as the return value of the .BR pcap_datalink (3PCAP) routine, a value that indicates the type of link-layer header at the beginning of the packets it provides. This is not necessarily the type of link-layer header that the packets being captured have on the network from which they're being captured; for example, packets from an IEEE 802.11 network might be provided by libpcap with Ethernet headers that the network adapter or the network adapter driver generates from the 802.11 headers. The names for those values begin with .BR DLT_ , so they are sometimes called "DLT_ values". .PP The values stored in the link-layer header type field in the savefile header are, in most but not all cases, the same as the values returned by .BR pcap_datalink() . The names for those values begin with .BR LINKTYPE_ . .PP The link-layer header types supported by libpcap are described at http://www.tcpdump.org/linktypes.html. .SH SEE ALSO pcap_datalink(3PCAP) libpcap-1.8.1/pcap_set_snaplen.3pcap0000644000026300017510000000336713003771737015545 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_SET_SNAPLEN 3PCAP "3 January 2014" .SH NAME pcap_set_snaplen \- set the snapshot length for a not-yet-activated capture handle .SH SYNOPSIS .nf .ft B #include .LP .ft B int pcap_set_snaplen(pcap_t *p, int snaplen); .ft .fi .SH DESCRIPTION .B pcap_set_snaplen() sets the snapshot length to be used on a capture handle when the handle is activated to .IR snaplen . .SH RETURN VALUE .B pcap_set_snaplen() returns 0 on success or .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) libpcap-1.8.1/arcnet.h0000644000026300017510000000461513003771737012721 0ustar mcrmcr/* * Copyright (c) 1982, 1986, 1993 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp */ /* RFC 1051 */ #define ARCTYPE_IP_OLD 240 /* IP protocol */ #define ARCTYPE_ARP_OLD 241 /* address resolution protocol */ /* RFC 1201 */ #define ARCTYPE_IP 212 /* IP protocol */ #define ARCTYPE_ARP 213 /* address resolution protocol */ #define ARCTYPE_REVARP 214 /* reverse addr resolution protocol */ #define ARCTYPE_ATALK 221 /* Appletalk */ #define ARCTYPE_BANIAN 247 /* Banyan Vines */ #define ARCTYPE_IPX 250 /* Novell IPX */ #define ARCTYPE_INET6 0xc4 /* IPng */ #define ARCTYPE_DIAGNOSE 0x80 /* as per ANSI/ATA 878.1 */ libpcap-1.8.1/pcap-pf.c0000644000026300017510000004220413003771737012762 0ustar mcrmcr/* * Copyright (c) 1990, 1991, 1992, 1993, 1994, 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. * * packet filter subroutines for tcpdump * Extraction/creation by Jeffrey Mogul, DECWRL */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include struct mbuf; struct rtentry; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the * native OS version, as we need various BPF ioctls from it. */ #define PCAP_DONT_INCLUDE_PCAP_BPF_H #include #include "pcap-int.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif /* * FDDI packets are padded to make everything line up on a nice boundary. */ #define PCAP_FDDIPAD 3 /* * Private data for capturing on Ultrix and DEC OSF/1^WDigital UNIX^W^W * Tru64 UNIX packetfilter devices. */ struct pcap_pf { int filtering_in_kernel; /* using kernel filter */ u_long TotPkts; /* can't oflow for 79 hrs on ether */ u_long TotAccepted; /* count accepted by filter */ u_long TotDrops; /* count of dropped packets */ long TotMissed; /* missed by i/f during this run */ long OrigMissed; /* missed by i/f before this run */ }; static int pcap_setfilter_pf(pcap_t *, struct bpf_program *); /* * BUFSPACE is the size in bytes of the packet read buffer. Most tcpdump * applications aren't going to need more than 200 bytes of packet header * and the read shouldn't return more packets than packetfilter's internal * queue limit (bounded at 256). */ #define BUFSPACE (200 * 256) static int pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user) { struct pcap_pf *pf = pc->priv; register u_char *p, *bp; register int cc, n, buflen, inc; register struct enstamp *sp; #ifdef LBL_ALIGN struct enstamp stamp; #endif register u_int pad; again: cc = pc->cc; if (cc == 0) { cc = read(pc->fd, (char *)pc->buffer + pc->offset, pc->bufsize); if (cc < 0) { if (errno == EWOULDBLOCK) return (0); if (errno == EINVAL && lseek(pc->fd, 0L, SEEK_CUR) + pc->bufsize < 0) { /* * Due to a kernel bug, after 2^31 bytes, * the kernel file offset overflows and * read fails with EINVAL. The lseek() * to 0 will fix things. */ (void)lseek(pc->fd, 0L, SEEK_SET); goto again; } pcap_snprintf(pc->errbuf, sizeof(pc->errbuf), "pf read: %s", pcap_strerror(errno)); return (-1); } bp = (u_char *)pc->buffer + pc->offset; } else bp = pc->bp; /* * Loop through each packet. */ n = 0; pad = pc->fddipad; while (cc > 0) { /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return -2 to indicate * that we were told to break out of the loop, otherwise * leave the flag set, so that the *next* call will break * out of the loop without having read any packets, and * return the number of packets we've processed so far. */ if (pc->break_loop) { if (n == 0) { pc->break_loop = 0; return (-2); } else { pc->cc = cc; pc->bp = bp; return (n); } } if (cc < sizeof(*sp)) { pcap_snprintf(pc->errbuf, sizeof(pc->errbuf), "pf short read (%d)", cc); return (-1); } #ifdef LBL_ALIGN if ((long)bp & 3) { sp = &stamp; memcpy((char *)sp, (char *)bp, sizeof(*sp)); } else #endif sp = (struct enstamp *)bp; if (sp->ens_stamplen != sizeof(*sp)) { pcap_snprintf(pc->errbuf, sizeof(pc->errbuf), "pf short stamplen (%d)", sp->ens_stamplen); return (-1); } p = bp + sp->ens_stamplen; buflen = sp->ens_count; if (buflen > pc->snapshot) buflen = pc->snapshot; /* Calculate inc before possible pad update */ inc = ENALIGN(buflen + sp->ens_stamplen); cc -= inc; bp += inc; pf->TotPkts++; pf->TotDrops += sp->ens_dropped; pf->TotMissed = sp->ens_ifoverflows; if (pf->OrigMissed < 0) pf->OrigMissed = pf->TotMissed; /* * Short-circuit evaluation: if using BPF filter * in kernel, no need to do it now - we already know * the packet passed the filter. * * Note: the filter code was generated assuming * that pc->fddipad was the amount of padding * before the header, as that's what's required * in the kernel, so we run the filter before * skipping that padding. */ if (pf->filtering_in_kernel || bpf_filter(pc->fcode.bf_insns, p, sp->ens_count, buflen)) { struct pcap_pkthdr h; pf->TotAccepted++; h.ts = sp->ens_tstamp; h.len = sp->ens_count - pad; p += pad; buflen -= pad; h.caplen = buflen; (*callback)(user, &h, p); if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { pc->cc = cc; pc->bp = bp; return (n); } } } pc->cc = 0; return (n); } static int pcap_inject_pf(pcap_t *p, const void *buf, size_t size) { int ret; ret = write(p->fd, buf, size); if (ret == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", pcap_strerror(errno)); return (-1); } return (ret); } static int pcap_stats_pf(pcap_t *p, struct pcap_stat *ps) { struct pcap_pf *pf = p->priv; /* * If packet filtering is being done in the kernel: * * "ps_recv" counts only packets that passed the filter. * This does not include packets dropped because we * ran out of buffer space. (XXX - perhaps it should, * by adding "ps_drop" to "ps_recv", for compatibility * with some other platforms. On the other hand, on * some platforms "ps_recv" counts only packets that * passed the filter, and on others it counts packets * that didn't pass the filter....) * * "ps_drop" counts packets that passed the kernel filter * (if any) but were dropped because the input queue was * full. * * "ps_ifdrop" counts packets dropped by the network * inteface (regardless of whether they would have passed * the input filter, of course). * * If packet filtering is not being done in the kernel: * * "ps_recv" counts only packets that passed the filter. * * "ps_drop" counts packets that were dropped because the * input queue was full, regardless of whether they passed * the userland filter. * * "ps_ifdrop" counts packets dropped by the network * inteface (regardless of whether they would have passed * the input filter, of course). * * These statistics don't include packets not yet read from * the kernel by libpcap, but they may include packets not * yet read from libpcap by the application. */ ps->ps_recv = pf->TotAccepted; ps->ps_drop = pf->TotDrops; ps->ps_ifdrop = pf->TotMissed - pf->OrigMissed; return (0); } /* * We include the OS's , not our "pcap/bpf.h", so we probably * don't get DLT_DOCSIS defined. */ #ifndef DLT_DOCSIS #define DLT_DOCSIS 143 #endif static int pcap_activate_pf(pcap_t *p) { struct pcap_pf *pf = p->priv; short enmode; int backlog = -1; /* request the most */ struct enfilter Filter; struct endevp devparams; /* * Initially try a read/write open (to allow the inject * method to work). If that fails due to permission * issues, fall back to read-only. This allows a * non-root user to be granted specific access to pcap * capabilities via file permissions. * * XXX - we should have an API that has a flag that * controls whether to open read-only or read-write, * so that denial of permission to send (or inability * to send, if sending packets isn't supported on * the device in question) can be indicated at open * time. * * XXX - we assume here that "pfopen()" does not, in fact, modify * its argument, even though it takes a "char *" rather than a * "const char *" as its first argument. That appears to be * the case, at least on Digital UNIX 4.0. * * XXX - is there an error that means "no such device"? Is * there one that means "that device doesn't support pf"? */ p->fd = pfopen(p->opt.device, O_RDWR); if (p->fd == -1 && errno == EACCES) p->fd = pfopen(p->opt.device, O_RDONLY); if (p->fd < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "pf open: %s: %s\n\ your system may not be properly configured; see the packetfilter(4) man page\n", p->opt.device, pcap_strerror(errno)); goto bad; } pf->OrigMissed = -1; enmode = ENTSTAMP|ENNONEXCL; if (!p->opt.immediate) enmode |= ENBATCH; if (p->opt.promisc) enmode |= ENPROMISC; if (ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCMBIS: %s", pcap_strerror(errno)); goto bad; } #ifdef ENCOPYALL /* Try to set COPYALL mode so that we see packets to ourself */ enmode = ENCOPYALL; (void)ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode);/* OK if this fails */ #endif /* set the backlog */ if (ioctl(p->fd, EIOCSETW, (caddr_t)&backlog) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCSETW: %s", pcap_strerror(errno)); goto bad; } /* discover interface type */ if (ioctl(p->fd, EIOCDEVP, (caddr_t)&devparams) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCDEVP: %s", pcap_strerror(errno)); goto bad; } /* HACK: to compile prior to Ultrix 4.2 */ #ifndef ENDT_FDDI #define ENDT_FDDI 4 #endif switch (devparams.end_dev_type) { case ENDT_10MB: p->linktype = DLT_EN10MB; p->offset = 2; /* * This is (presumably) a real Ethernet capture; give it a * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so * that an application can let you choose it, in case you're * capturing DOCSIS traffic that a Cisco Cable Modem * Termination System is putting out onto an Ethernet (it * doesn't put an Ethernet header onto the wire, it puts raw * DOCSIS frames out on the wire inside the low-level * Ethernet framing). */ p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (p->dlt_list != NULL) { p->dlt_list[0] = DLT_EN10MB; p->dlt_list[1] = DLT_DOCSIS; p->dlt_count = 2; } break; case ENDT_FDDI: p->linktype = DLT_FDDI; break; #ifdef ENDT_SLIP case ENDT_SLIP: p->linktype = DLT_SLIP; break; #endif #ifdef ENDT_PPP case ENDT_PPP: p->linktype = DLT_PPP; break; #endif #ifdef ENDT_LOOPBACK case ENDT_LOOPBACK: /* * It appears to use Ethernet framing, at least on * Digital UNIX 4.0. */ p->linktype = DLT_EN10MB; p->offset = 2; break; #endif #ifdef ENDT_TRN case ENDT_TRN: p->linktype = DLT_IEEE802; break; #endif default: /* * XXX - what about ENDT_IEEE802? The pfilt.h header * file calls this "IEEE 802 networks (non-Ethernet)", * but that doesn't specify a specific link layer type; * it could be 802.4, or 802.5 (except that 802.5 is * ENDT_TRN), or 802.6, or 802.11, or.... That's why * DLT_IEEE802 was hijacked to mean Token Ring in various * BSDs, and why we went along with that hijacking. * * XXX - what about ENDT_HDLC and ENDT_NULL? * Presumably, as ENDT_OTHER is just "Miscellaneous * framing", there's not much we can do, as that * doesn't specify a particular type of header. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown data-link type %u", devparams.end_dev_type); goto bad; } /* set truncation */ if (p->linktype == DLT_FDDI) { p->fddipad = PCAP_FDDIPAD; /* packetfilter includes the padding in the snapshot */ p->snapshot += PCAP_FDDIPAD; } else p->fddipad = 0; if (ioctl(p->fd, EIOCTRUNCATE, (caddr_t)&p->snapshot) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCTRUNCATE: %s", pcap_strerror(errno)); goto bad; } /* accept all packets */ memset(&Filter, 0, sizeof(Filter)); Filter.enf_Priority = 37; /* anything > 2 */ Filter.enf_FilterLen = 0; /* means "always true" */ if (ioctl(p->fd, EIOCSETF, (caddr_t)&Filter) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCSETF: %s", pcap_strerror(errno)); goto bad; } if (p->opt.timeout != 0) { struct timeval timeout; timeout.tv_sec = p->opt.timeout / 1000; timeout.tv_usec = (p->opt.timeout * 1000) % 1000000; if (ioctl(p->fd, EIOCSRTIMEOUT, (caddr_t)&timeout) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCSRTIMEOUT: %s", pcap_strerror(errno)); goto bad; } } p->bufsize = BUFSPACE; p->buffer = malloc(p->bufsize + p->offset); if (p->buffer == NULL) { strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); goto bad; } /* * "select()" and "poll()" work on packetfilter devices. */ p->selectable_fd = p->fd; p->read_op = pcap_read_pf; p->inject_op = pcap_inject_pf; p->setfilter_op = pcap_setfilter_pf; p->setdirection_op = NULL; /* Not implemented. */ p->set_datalink_op = NULL; /* can't change data link type */ p->getnonblock_op = pcap_getnonblock_fd; p->setnonblock_op = pcap_setnonblock_fd; p->stats_op = pcap_stats_pf; return (0); bad: pcap_cleanup_live_common(p); return (PCAP_ERROR); } pcap_t * pcap_create_interface(const char *device _U_, char *ebuf) { pcap_t *p; p = pcap_create_common(ebuf, sizeof (struct pcap_pf)); if (p == NULL) return (NULL); p->activate_op = pcap_activate_pf; return (p); } /* * XXX - is there an error from pfopen() that means "no such device"? * Is there one that means "that device doesn't support pf"? */ static int can_be_bound(const char *name _U_) { return (1); } int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { return (pcap_findalldevs_interfaces(alldevsp, errbuf, can_be_bound)); } static int pcap_setfilter_pf(pcap_t *p, struct bpf_program *fp) { struct pcap_pf *pf = p->priv; struct bpf_version bv; /* * See if BIOCVERSION works. If not, we assume the kernel doesn't * support BPF-style filters (it's not documented in the bpf(7) * or packetfiler(7) man pages, but the code used to fail if * BIOCSETF worked but BIOCVERSION didn't, and I've seen it do * kernel filtering in DU 4.0, so presumably BIOCVERSION works * there, at least). */ if (ioctl(p->fd, BIOCVERSION, (caddr_t)&bv) >= 0) { /* * OK, we have the version of the BPF interpreter; * is it the same major version as us, and the same * or better minor version? */ if (bv.bv_major == BPF_MAJOR_VERSION && bv.bv_minor >= BPF_MINOR_VERSION) { /* * Yes. Try to install the filter. */ if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) { pcap_snprintf(p->errbuf, sizeof(p->errbuf), "BIOCSETF: %s", pcap_strerror(errno)); return (-1); } /* * OK, that succeeded. We're doing filtering in * the kernel. (We assume we don't have a * userland filter installed - that'd require * a previous version check to have failed but * this one to succeed.) * * XXX - this message should be supplied to the * application as a warning of some sort, * except that if it's a GUI application, it's * not clear that it should be displayed in * a window to annoy the user. */ fprintf(stderr, "tcpdump: Using kernel BPF filter\n"); pf->filtering_in_kernel = 1; /* * Discard any previously-received packets, * as they might have passed whatever filter * was formerly in effect, but might not pass * this filter (BIOCSETF discards packets buffered * in the kernel, so you can lose packets in any * case). */ p->cc = 0; return (0); } /* * We can't use the kernel's BPF interpreter; don't give * up, just log a message and be inefficient. * * XXX - this should really be supplied to the application * as a warning of some sort. */ fprintf(stderr, "tcpdump: Requires BPF language %d.%d or higher; kernel is %d.%d\n", BPF_MAJOR_VERSION, BPF_MINOR_VERSION, bv.bv_major, bv.bv_minor); } /* * We couldn't do filtering in the kernel; do it in userland. */ if (install_bpf_program(p, fp) < 0) return (-1); /* * XXX - this message should be supplied by the application as * a warning of some sort. */ fprintf(stderr, "tcpdump: Filtering in user process\n"); pf->filtering_in_kernel = 0; return (0); } libpcap-1.8.1/pcap_create.3pcap0000644000026300017510000000433013003771737014464 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_CREATE 3PCAP "3 January 2014" .SH NAME pcap_create \- create a live capture handle .SH SYNOPSIS .nf .ft B #include .ft .LP .nf .ft B char errbuf[PCAP_ERRBUF_SIZE]; .ft .LP .ft B pcap_t *pcap_create(const char *source, char *errbuf); .ft .fi .SH DESCRIPTION .B pcap_create() is used to create a packet capture handle to look at packets on the network. .I source is a string that specifies the network device to open; on Linux systems with 2.2 or later kernels, a .I source argument of "any" or .B NULL can be used to capture packets from all interfaces. .PP The returned handle must be activated with .B pcap_activate() before packets can be captured with it; options for the capture, such as promiscuous mode, can be set on the handle before activating it. .SH RETURN VALUE .B pcap_create() returns a .I pcap_t * on success and .B NULL on failure. If .B NULL is returned, .I errbuf is filled in with an appropriate error message. .I errbuf is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. .SH SEE ALSO pcap(3PCAP), pcap_activate(3PCAP) libpcap-1.8.1/pcap_statustostr.3pcap0000644000026300017510000000307013003771737015640 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_STATUSTOSTR 3PCAP "3 January 2014" .SH NAME pcap_statustostr \- convert a PCAP_ERROR_ or PCAP_WARNING_ value to a string .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B const char *pcap_statustostr(int error); .ft .fi .SH DESCRIPTION .B pcap_statustostr() converts a .B PCAP_ERROR_ or .B PCAP_WARNING_ value returned by a libpcap routine to an error string. .SH SEE ALSO pcap(3PCAP) libpcap-1.8.1/mkdep0000755000026300017510000000467513003771737012330 0ustar mcrmcr#!/bin/sh - # # Copyright (c) 1994, 1996 # The Regents of the University of California. All rights reserved. # # Redistribution and use in source and binary forms are permitted # provided that this notice is preserved and that due credit is given # to the University of California at Berkeley. The name of the University # may not be used to endorse or promote products derived from this # software without specific prior written permission. This software # is provided ``as is'' without express or implied warranty. # # @(#)mkdep.sh 5.11 (Berkeley) 5/5/88 # MAKE=Makefile # default makefile name is "Makefile" CC=cc # default C compiler is "cc" DEPENDENCY_CFLAG=-M # default dependency-generation flag is -M while : do case "$1" in # -c allows you to specify the C compiler -c) CC=$2 shift; shift ;; # -f allows you to select a makefile name -f) MAKE=$2 shift; shift ;; # -m allows you to specify the dependency-generation flag -m) DEPENDENCY_CFLAG=$2 shift; shift ;; # the -p flag produces "program: program.c" style dependencies # so .o's don't get produced -p) SED='s;\.o;;' shift ;; *) break ;; esac done if [ $# = 0 ] ; then echo 'usage: mkdep [-p] [-c cc] [-f makefile] [-m dependency-cflag] [flags] file ...' exit 1 fi if [ ! -w $MAKE ]; then echo "mkdep: no writeable file \"$MAKE\"" exit 1 fi TMP=/tmp/mkdep$$ trap 'rm -f $TMP ; exit 1' 1 2 3 13 15 cp $MAKE ${MAKE}.bak sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP cat << _EOF_ >> $TMP # DO NOT DELETE THIS LINE -- mkdep uses it. # DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. _EOF_ # If your compiler doesn't have -M, add it. If you can't, the next two # lines will try and replace the "cc -M". The real problem is that this # hack can't deal with anything that requires a search path, and doesn't # even try for anything using bracket (<>) syntax. # # egrep '^#include[ ]*".*"' /dev/null $* | # sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' | # XXX this doesn't work with things like "-DDECLWAITSTATUS=union\ wait" $CC $DEPENDENCY_CFLAG $* | sed " s; \./; ;g $SED" | awk '{ if ($1 != prev) { if (rec != "") print rec; rec = $0; prev = $1; } else { if (length(rec $2) > 78) { print rec; rec = $0; } else rec = rec " " $2 } } END { print rec }' >> $TMP cat << _EOF_ >> $TMP # IF YOU PUT ANYTHING HERE IT WILL GO AWAY _EOF_ # copy to preserve permissions cp $TMP $MAKE rm -f ${MAKE}.bak $TMP exit 0 libpcap-1.8.1/bpf_image.c0000644000026300017510000001246213003771737013350 0ustar mcrmcr/* * Copyright (c) 1990, 1991, 1992, 1994, 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef _WIN32 #include #else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_BITYPES_H #include #endif #include #endif /* _WIN32 */ #include #include #include "pcap-int.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif char * bpf_image(p, n) const struct bpf_insn *p; int n; { int v; const char *fmt, *op; static char image[256]; char operand[64]; v = p->k; switch (p->code) { default: op = "unimp"; fmt = "0x%x"; v = p->code; break; case BPF_RET|BPF_K: op = "ret"; fmt = "#%d"; break; case BPF_RET|BPF_A: op = "ret"; fmt = ""; break; case BPF_LD|BPF_W|BPF_ABS: op = "ld"; fmt = "[%d]"; break; case BPF_LD|BPF_H|BPF_ABS: op = "ldh"; fmt = "[%d]"; break; case BPF_LD|BPF_B|BPF_ABS: op = "ldb"; fmt = "[%d]"; break; case BPF_LD|BPF_W|BPF_LEN: op = "ld"; fmt = "#pktlen"; break; case BPF_LD|BPF_W|BPF_IND: op = "ld"; fmt = "[x + %d]"; break; case BPF_LD|BPF_H|BPF_IND: op = "ldh"; fmt = "[x + %d]"; break; case BPF_LD|BPF_B|BPF_IND: op = "ldb"; fmt = "[x + %d]"; break; case BPF_LD|BPF_IMM: op = "ld"; fmt = "#0x%x"; break; case BPF_LDX|BPF_IMM: op = "ldx"; fmt = "#0x%x"; break; case BPF_LDX|BPF_MSH|BPF_B: op = "ldxb"; fmt = "4*([%d]&0xf)"; break; case BPF_LD|BPF_MEM: op = "ld"; fmt = "M[%d]"; break; case BPF_LDX|BPF_MEM: op = "ldx"; fmt = "M[%d]"; break; case BPF_ST: op = "st"; fmt = "M[%d]"; break; case BPF_STX: op = "stx"; fmt = "M[%d]"; break; case BPF_JMP|BPF_JA: op = "ja"; fmt = "%d"; v = n + 1 + p->k; break; case BPF_JMP|BPF_JGT|BPF_K: op = "jgt"; fmt = "#0x%x"; break; case BPF_JMP|BPF_JGE|BPF_K: op = "jge"; fmt = "#0x%x"; break; case BPF_JMP|BPF_JEQ|BPF_K: op = "jeq"; fmt = "#0x%x"; break; case BPF_JMP|BPF_JSET|BPF_K: op = "jset"; fmt = "#0x%x"; break; case BPF_JMP|BPF_JGT|BPF_X: op = "jgt"; fmt = "x"; break; case BPF_JMP|BPF_JGE|BPF_X: op = "jge"; fmt = "x"; break; case BPF_JMP|BPF_JEQ|BPF_X: op = "jeq"; fmt = "x"; break; case BPF_JMP|BPF_JSET|BPF_X: op = "jset"; fmt = "x"; break; case BPF_ALU|BPF_ADD|BPF_X: op = "add"; fmt = "x"; break; case BPF_ALU|BPF_SUB|BPF_X: op = "sub"; fmt = "x"; break; case BPF_ALU|BPF_MUL|BPF_X: op = "mul"; fmt = "x"; break; case BPF_ALU|BPF_DIV|BPF_X: op = "div"; fmt = "x"; break; case BPF_ALU|BPF_MOD|BPF_X: op = "mod"; fmt = "x"; break; case BPF_ALU|BPF_AND|BPF_X: op = "and"; fmt = "x"; break; case BPF_ALU|BPF_OR|BPF_X: op = "or"; fmt = "x"; break; case BPF_ALU|BPF_XOR|BPF_X: op = "xor"; fmt = "x"; break; case BPF_ALU|BPF_LSH|BPF_X: op = "lsh"; fmt = "x"; break; case BPF_ALU|BPF_RSH|BPF_X: op = "rsh"; fmt = "x"; break; case BPF_ALU|BPF_ADD|BPF_K: op = "add"; fmt = "#%d"; break; case BPF_ALU|BPF_SUB|BPF_K: op = "sub"; fmt = "#%d"; break; case BPF_ALU|BPF_MUL|BPF_K: op = "mul"; fmt = "#%d"; break; case BPF_ALU|BPF_DIV|BPF_K: op = "div"; fmt = "#%d"; break; case BPF_ALU|BPF_MOD|BPF_K: op = "mod"; fmt = "#%d"; break; case BPF_ALU|BPF_AND|BPF_K: op = "and"; fmt = "#0x%x"; break; case BPF_ALU|BPF_OR|BPF_K: op = "or"; fmt = "#0x%x"; break; case BPF_ALU|BPF_XOR|BPF_K: op = "xor"; fmt = "#0x%x"; break; case BPF_ALU|BPF_LSH|BPF_K: op = "lsh"; fmt = "#%d"; break; case BPF_ALU|BPF_RSH|BPF_K: op = "rsh"; fmt = "#%d"; break; case BPF_ALU|BPF_NEG: op = "neg"; fmt = ""; break; case BPF_MISC|BPF_TAX: op = "tax"; fmt = ""; break; case BPF_MISC|BPF_TXA: op = "txa"; fmt = ""; break; } (void)pcap_snprintf(operand, sizeof operand, fmt, v); if (BPF_CLASS(p->code) == BPF_JMP && BPF_OP(p->code) != BPF_JA) { (void)pcap_snprintf(image, sizeof image, "(%03d) %-8s %-16s jt %d\tjf %d", n, op, operand, n + 1 + p->jt, n + 1 + p->jf); } else { (void)pcap_snprintf(image, sizeof image, "(%03d) %-8s %s", n, op, operand); } return image; } libpcap-1.8.1/pcap-snit.c0000644000026300017510000002742413003771737013341 0ustar mcrmcr/* * Copyright (c) 1990, 1991, 1992, 1993, 1994, 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. * * Modifications made to accommodate the new SunOS4.0 NIT facility by * Micky Liu, micky@cunixc.cc.columbia.edu, Columbia University in May, 1989. * This module now handles the STREAMS based NIT. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcap-int.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif /* * The chunk size for NIT. This is the amount of buffering * done for read calls. */ #define CHUNKSIZE (2*1024) /* * The total buffer space used by NIT. */ #define BUFSPACE (4*CHUNKSIZE) /* Forwards */ static int nit_setflags(int, int, int, char *); /* * Private data for capturing on STREAMS NIT devices. */ struct pcap_snit { struct pcap_stat stat; }; static int pcap_stats_snit(pcap_t *p, struct pcap_stat *ps) { struct pcap_snit *psn = p->priv; /* * "ps_recv" counts packets handed to the filter, not packets * that passed the filter. As filtering is done in userland, * this does not include packets dropped because we ran out * of buffer space. * * "ps_drop" counts packets dropped inside the "/dev/nit" * device because of flow control requirements or resource * exhaustion; it doesn't count packets dropped by the * interface driver, or packets dropped upstream. As filtering * is done in userland, it counts packets regardless of whether * they would've passed the filter. * * These statistics don't include packets not yet read from the * kernel by libpcap or packets not yet read from libpcap by the * application. */ *ps = psn->stat; return (0); } static int pcap_read_snit(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct pcap_snit *psn = p->priv; register int cc, n; register u_char *bp, *cp, *ep; register struct nit_bufhdr *hdrp; register struct nit_iftime *ntp; register struct nit_iflen *nlp; register struct nit_ifdrops *ndp; register int caplen; cc = p->cc; if (cc == 0) { cc = read(p->fd, (char *)p->buffer, p->bufsize); if (cc < 0) { if (errno == EWOULDBLOCK) return (0); pcap_snprintf(p->errbuf, sizeof(p->errbuf), "pcap_read: %s", pcap_strerror(errno)); return (-1); } bp = (u_char *)p->buffer; } else bp = p->bp; /* * loop through each snapshot in the chunk */ n = 0; ep = bp + cc; while (bp < ep) { /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return -2 to indicate * that we were told to break out of the loop, otherwise * leave the flag set, so that the *next* call will break * out of the loop without having read any packets, and * return the number of packets we've processed so far. */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return (-2); } else { p->bp = bp; p->cc = ep - bp; return (n); } } ++psn->stat.ps_recv; cp = bp; /* get past NIT buffer */ hdrp = (struct nit_bufhdr *)cp; cp += sizeof(*hdrp); /* get past NIT timer */ ntp = (struct nit_iftime *)cp; cp += sizeof(*ntp); ndp = (struct nit_ifdrops *)cp; psn->stat.ps_drop = ndp->nh_drops; cp += sizeof *ndp; /* get past packet len */ nlp = (struct nit_iflen *)cp; cp += sizeof(*nlp); /* next snapshot */ bp += hdrp->nhb_totlen; caplen = nlp->nh_pktlen; if (caplen > p->snapshot) caplen = p->snapshot; if (bpf_filter(p->fcode.bf_insns, cp, nlp->nh_pktlen, caplen)) { struct pcap_pkthdr h; h.ts = ntp->nh_timestamp; h.len = nlp->nh_pktlen; h.caplen = caplen; (*callback)(user, &h, cp); if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { p->cc = ep - bp; p->bp = bp; return (n); } } } p->cc = 0; return (n); } static int pcap_inject_snit(pcap_t *p, const void *buf, size_t size) { struct strbuf ctl, data; /* * XXX - can we just do * ret = write(pd->f, buf, size); */ ctl.len = sizeof(*sa); /* XXX - what was this? */ ctl.buf = (char *)sa; data.buf = buf; data.len = size; ret = putmsg(p->fd, &ctl, &data); if (ret == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", pcap_strerror(errno)); return (-1); } return (ret); } static int nit_setflags(pcap_t *p) { bpf_u_int32 flags; struct strioctl si; u_int zero = 0; struct timeval timeout; if (p->opt.immediate) { /* * Set the chunk size to zero, so that chunks get sent * up immediately. */ si.ic_cmd = NIOCSCHUNK; si.ic_len = sizeof(zero); si.ic_dp = (char *)&zero; if (ioctl(p->fd, I_STR, (char *)&si) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCSCHUNK: %s", pcap_strerror(errno)); return (-1); } } si.ic_timout = INFTIM; if (p->opt.timeout != 0) { timeout.tv_sec = p->opt.timeout / 1000; timeout.tv_usec = (p->opt.timeout * 1000) % 1000000; si.ic_cmd = NIOCSTIME; si.ic_len = sizeof(timeout); si.ic_dp = (char *)&timeout; if (ioctl(p->fd, I_STR, (char *)&si) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCSTIME: %s", pcap_strerror(errno)); return (-1); } } flags = NI_TIMESTAMP | NI_LEN | NI_DROPS; if (p->opt.promisc) flags |= NI_PROMISC; si.ic_cmd = NIOCSFLAGS; si.ic_len = sizeof(flags); si.ic_dp = (char *)&flags; if (ioctl(p->fd, I_STR, (char *)&si) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCSFLAGS: %s", pcap_strerror(errno)); return (-1); } return (0); } static int pcap_activate_snit(pcap_t *p) { struct strioctl si; /* struct for ioctl() */ struct ifreq ifr; /* interface request struct */ int chunksize = CHUNKSIZE; int fd; static const char dev[] = "/dev/nit"; if (p->opt.rfmon) { /* * No monitor mode on SunOS 4.x (no Wi-Fi devices on * hardware supported by SunOS 4.x). */ return (PCAP_ERROR_RFMON_NOTSUP); } if (p->snapshot < 96) /* * NIT requires a snapshot length of at least 96. */ p->snapshot = 96; /* * Initially try a read/write open (to allow the inject * method to work). If that fails due to permission * issues, fall back to read-only. This allows a * non-root user to be granted specific access to pcap * capabilities via file permissions. * * XXX - we should have an API that has a flag that * controls whether to open read-only or read-write, * so that denial of permission to send (or inability * to send, if sending packets isn't supported on * the device in question) can be indicated at open * time. */ p->fd = fd = open(dev, O_RDWR); if (fd < 0 && errno == EACCES) p->fd = fd = open(dev, O_RDONLY); if (fd < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", dev, pcap_strerror(errno)); goto bad; } /* arrange to get discrete messages from the STREAM and use NIT_BUF */ if (ioctl(fd, I_SRDOPT, (char *)RMSGD) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "I_SRDOPT: %s", pcap_strerror(errno)); goto bad; } if (ioctl(fd, I_PUSH, "nbuf") < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "push nbuf: %s", pcap_strerror(errno)); goto bad; } /* set the chunksize */ si.ic_cmd = NIOCSCHUNK; si.ic_timout = INFTIM; si.ic_len = sizeof(chunksize); si.ic_dp = (char *)&chunksize; if (ioctl(fd, I_STR, (char *)&si) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCSCHUNK: %s", pcap_strerror(errno)); goto bad; } /* request the interface */ strncpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; si.ic_cmd = NIOCBIND; si.ic_len = sizeof(ifr); si.ic_dp = (char *)𝔦 if (ioctl(fd, I_STR, (char *)&si) < 0) { /* * XXX - is there an error that means "no such device"? * Is there one that means "that device doesn't support * STREAMS NIT"? */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCBIND: %s: %s", ifr.ifr_name, pcap_strerror(errno)); goto bad; } /* set the snapshot length */ si.ic_cmd = NIOCSSNAP; si.ic_len = sizeof(p->snapshot); si.ic_dp = (char *)&p->snapshot; if (ioctl(fd, I_STR, (char *)&si) < 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCSSNAP: %s", pcap_strerror(errno)); goto bad; } if (nit_setflags(p) < 0) goto bad; (void)ioctl(fd, I_FLUSH, (char *)FLUSHR); /* * NIT supports only ethernets. */ p->linktype = DLT_EN10MB; p->bufsize = BUFSPACE; p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); goto bad; } /* * "p->fd" is an FD for a STREAMS device, so "select()" and * "poll()" should work on it. */ p->selectable_fd = p->fd; /* * This is (presumably) a real Ethernet capture; give it a * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so * that an application can let you choose it, in case you're * capturing DOCSIS traffic that a Cisco Cable Modem * Termination System is putting out onto an Ethernet (it * doesn't put an Ethernet header onto the wire, it puts raw * DOCSIS frames out on the wire inside the low-level * Ethernet framing). */ p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (p->dlt_list != NULL) { p->dlt_list[0] = DLT_EN10MB; p->dlt_list[1] = DLT_DOCSIS; p->dlt_count = 2; } p->read_op = pcap_read_snit; p->inject_op = pcap_inject_snit; p->setfilter_op = install_bpf_program; /* no kernel filtering */ p->setdirection_op = NULL; /* Not implemented. */ p->set_datalink_op = NULL; /* can't change data link type */ p->getnonblock_op = pcap_getnonblock_fd; p->setnonblock_op = pcap_setnonblock_fd; p->stats_op = pcap_stats_snit; return (0); bad: pcap_cleanup_live_common(p); return (PCAP_ERROR); } pcap_t * pcap_create_interface(const char *device _U_, char *ebuf) { pcap_t *p; p = pcap_create_common(ebuf, sizeof (struct pcap_snit)); if (p == NULL) return (NULL); p->activate_op = pcap_activate_snit; return (p); } /* * XXX - there's probably a NIOCBIND error that means "that device * doesn't support NIT"; if so, we should try an NIOCBIND and use that. */ static int can_be_bound(const char *name _U_) { return (1); } int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { return (pcap_findalldevs_interfaces(alldevsp, errbuf, can_be_bound)); } libpcap-1.8.1/pcap-new.c0000644000026300017510000010445413003771737013154 0ustar mcrmcr/* * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino, CACE Technologies * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcap-int.h" // for the details of the pcap_t structure #include "pcap-rpcap.h" #include "sockutils.h" #include // for the errno variable #include // for malloc(), free(), ... #include // for strstr, etc #ifndef WIN32 #include // for readdir #endif /* Keeps a list of all the opened connections in the active mode. */ extern struct activehosts *activeHosts; /* * \brief Keeps the main socket identifier when we want to accept a new remote connection (active mode only). * See the documentation of pcap_remoteact_accept() and pcap_remoteact_cleanup() for more details. */ SOCKET sockmain; /* String identifier to be used in the pcap_findalldevs_ex() */ #define PCAP_TEXT_SOURCE_FILE "File" /* String identifier to be used in the pcap_findalldevs_ex() */ #define PCAP_TEXT_SOURCE_ADAPTER "Network adapter" /* String identifier to be used in the pcap_findalldevs_ex() */ #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host" /* String identifier to be used in the pcap_findalldevs_ex() */ #define PCAP_TEXT_SOURCE_ON_REMOTE_HOST "on remote node" /* * Private data for capturing on WinPcap devices. */ struct pcap_win { int nonblock; int rfmon_selfstart; /* a flag tells whether the monitor mode is set by itself */ int filtering_in_kernel; /* using kernel filter */ #ifdef HAVE_DAG_API int dag_fcs_bits; /* Number of checksum bits from link layer */ #endif }; /**************************************************** * * * Function bodies * * * ****************************************************/ int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf) { SOCKET sockctrl; /* socket descriptor of the control connection */ uint32 totread = 0; /* number of bytes of the payload read from the socket */ int nread; struct addrinfo hints; /* temp variable needed to resolve hostnames into to socket representation */ struct addrinfo *addrinfo; /* temp variable needed to resolve hostnames into to socket representation */ struct rpcap_header header; /* structure that keeps the general header of the rpcap protocol */ int i, j; /* temp variables */ int naddr; /* temp var needed to avoid problems with IPv6 addresses */ struct pcap_addr *addr; /* another such temp */ int retval; /* store the return value of the functions */ int nif; /* Number of interfaces listed */ int active = 0; /* 'true' if we the other end-party is in active mode */ char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE], name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE]; int type; pcap_t *fp; char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */ pcap_if_t *dev; /* Previous device into the pcap_if_t chain */ if (strlen(source) > PCAP_BUF_SIZE) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly."); return -1; } /* * Determine the type of the source (file, local, remote) * There are some differences if pcap_findalldevs_ex() is called to list files and remote adapters. * In the first case, the name of the directory we have to look into must be present (therefore * the 'name' parameter of the pcap_parsesrcstr() is present). * In the second case, the name of the adapter is not required (we need just the host). So, we have * to use a first time this function to get the source type, and a second time to get the appropriate * info, which depends on the source type. */ if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1) return -1; if (type == PCAP_SRC_IFLOCAL) { if (pcap_parsesrcstr(source, &type, host, NULL, NULL, errbuf) == -1) return -1; /* Initialize temporary string */ tmpstring[PCAP_BUF_SIZE] = 0; /* The user wants to retrieve adapters from a local host */ if (pcap_findalldevs(alldevs, errbuf) == -1) return -1; if ((alldevs == NULL) || (*alldevs == NULL)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "No interfaces found! Make sure libpcap/WinPcap is properly installed" " on the local machine."); return -1; } /* Scan all the interfaces and modify name and description */ /* This is a trick in order to avoid the re-implementation of the pcap_findalldevs here */ dev = *alldevs; while (dev) { /* Create the new device identifier */ if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1) return -1; /* Delete the old pointer */ free(dev->name); /* Make a copy of the new device identifier */ dev->name = strdup(tmpstring); if (dev->name == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); return -1; } /* Create the new device description */ if ((dev->description == NULL) || (dev->description[0] == 0)) pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER, dev->name, PCAP_TEXT_SOURCE_ON_LOCAL_HOST); else pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER, dev->description, PCAP_TEXT_SOURCE_ON_LOCAL_HOST); /* Delete the old pointer */ free(dev->description); /* Make a copy of the description */ dev->description = strdup(tmpstring); if (dev->description == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); return -1; } dev = dev->next; } return 0; } (*alldevs) = NULL; if (type == PCAP_SRC_FILE) { size_t stringlen; #ifdef WIN32 WIN32_FIND_DATA filedata; HANDLE filehandle; #else struct dirent *filedata; DIR *unixdir; #endif if (pcap_parsesrcstr(source, &type, host, port, name, errbuf) == -1) return -1; /* Check that the filename is correct */ stringlen = strlen(name); /* The directory must end with '\' in Win32 and '/' in UNIX */ #ifdef WIN32 #define ENDING_CHAR '\\' #else #define ENDING_CHAR '/' #endif if (name[stringlen - 1] != ENDING_CHAR) { name[stringlen] = ENDING_CHAR; name[stringlen + 1] = 0; stringlen++; } /* Save the path for future reference */ pcap_snprintf(path, sizeof(path), "%s", name); #ifdef WIN32 /* To perform directory listing, Win32 must have an 'asterisk' as ending char */ if (name[stringlen - 1] != '*') { name[stringlen] = '*'; name[stringlen + 1] = 0; } filehandle = FindFirstFile(name, &filedata); if (filehandle == INVALID_HANDLE_VALUE) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path); return -1; } #else /* opening the folder */ unixdir= opendir(path); /* get the first file into it */ filedata= readdir(unixdir); if (filedata == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path); return -1; } #endif do { #ifdef WIN32 pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName); #else pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name); #endif fp = pcap_open_offline(filename, errbuf); if (fp) { /* allocate the main structure */ if (*alldevs == NULL) /* This is in case it is the first file */ { (*alldevs) = (pcap_if_t *)malloc(sizeof(pcap_if_t)); dev = (*alldevs); } else { dev->next = (pcap_if_t *)malloc(sizeof(pcap_if_t)); dev = dev->next; } /* check that the malloc() didn't fail */ if (dev == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); return -1; } /* Initialize the structure to 'zero' */ memset(dev, 0, sizeof(pcap_if_t)); /* Create the new source identifier */ if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1) return -1; stringlen = strlen(tmpstring); dev->name = (char *)malloc(stringlen + 1); if (dev->name == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); return -1; } strlcpy(dev->name, tmpstring, stringlen); dev->name[stringlen] = 0; /* Create the description */ pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_FILE, filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST); stringlen = strlen(tmpstring); dev->description = (char *)malloc(stringlen + 1); if (dev->description == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); return -1; } /* Copy the new device description into the correct memory location */ strlcpy(dev->description, tmpstring, stringlen + 1); pcap_close(fp); } } #ifdef WIN32 while (FindNextFile(filehandle, &filedata) != 0); #else while ( (filedata= readdir(unixdir)) != NULL); #endif #ifdef WIN32 /* Close the search handle. */ FindClose(filehandle); #endif return 0; } /* If we come here, it is a remote host */ /* Retrieve the needed data for getting adapter list */ if (pcap_parsesrcstr(source, &type, host, port, NULL, errbuf) == -1) return -1; /* Warning: this call can be the first one called by the user. */ /* For this reason, we have to initialize the WinSock support. */ if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; /* Check for active mode */ sockctrl = rpcap_remoteact_getsock(host, &active, errbuf); if (sockctrl == INVALID_SOCKET) return -1; if (!active) { /* * We're not in active mode; let's try to open a new * control connection. */ addrinfo = NULL; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (port[0] == 0) { /* the user chose not to specify the port */ if (sock_initaddress(host, RPCAP_DEFAULT_NETPORT, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; } else { if (sock_initaddress(host, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; } if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == -1) goto error; /* addrinfo is no longer used */ freeaddrinfo(addrinfo); addrinfo = NULL; if (rpcap_sendauth(sockctrl, auth, errbuf) == -1) { sock_close(sockctrl, NULL, 0); return -1; } } /* RPCAP findalldevs command */ rpcap_createhdr(&header, RPCAP_MSG_FINDALLIF_REQ, 0, 0); if (sock_send(sockctrl, (char *)&header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) goto error; if (sock_recv(sockctrl, (char *)&header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1) goto error; /* Checks if the message is correct */ retval = rpcap_checkmsg(errbuf, sockctrl, &header, RPCAP_MSG_FINDALLIF_REPLY, RPCAP_MSG_ERROR, 0); if (retval != RPCAP_MSG_FINDALLIF_REPLY) /* the message is not the one expected */ { switch (retval) { case -3: /* Unrecoverable network error */ case -2: /* The other endpoint send a message that is not allowed here */ case -1: /* The other endpoint has a version number that is not compatible with our */ break; case RPCAP_MSG_ERROR: /* The other endpoint reported an error */ break; default: { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Internal error"); break; }; } if (!active) sock_close(sockctrl, NULL, 0); return -1; } /* read the number of interfaces */ nif = ntohs(header.value); /* loop until all interfaces have been received */ for (i = 0; i < nif; i++) { struct rpcap_findalldevs_if findalldevs_if; char tmpstring2[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */ size_t stringlen; tmpstring2[PCAP_BUF_SIZE] = 0; /* receive the findalldevs structure from remote host */ nread = sock_recv(sockctrl, (char *)&findalldevs_if, sizeof(struct rpcap_findalldevs_if), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE); if (nread == -1) goto error; totread += nread; findalldevs_if.namelen = ntohs(findalldevs_if.namelen); findalldevs_if.desclen = ntohs(findalldevs_if.desclen); findalldevs_if.naddr = ntohs(findalldevs_if.naddr); /* allocate the main structure */ if (i == 0) { (*alldevs) = (pcap_if_t *)malloc(sizeof(pcap_if_t)); dev = (*alldevs); } else { dev->next = (pcap_if_t *)malloc(sizeof(pcap_if_t)); dev = dev->next; } /* check that the malloc() didn't fail */ if (dev == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); goto error; } /* Initialize the structure to 'zero' */ memset(dev, 0, sizeof(pcap_if_t)); /* allocate mem for name and description */ if (findalldevs_if.namelen) { if (findalldevs_if.namelen >= sizeof(tmpstring)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface name too long"); goto error; } /* Retrieve adapter name */ nread = sock_recv(sockctrl, tmpstring, findalldevs_if.namelen, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE); if (nread == -1) goto error; totread += nread; tmpstring[findalldevs_if.namelen] = 0; /* Create the new device identifier */ if (pcap_createsrcstr(tmpstring2, PCAP_SRC_IFREMOTE, host, port, tmpstring, errbuf) == -1) return -1; stringlen = strlen(tmpstring2); dev->name = (char *)malloc(stringlen + 1); if (dev->name == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); goto error; } /* Copy the new device name into the correct memory location */ strlcpy(dev->name, tmpstring2, stringlen + 1); } if (findalldevs_if.desclen) { if (findalldevs_if.desclen >= sizeof(tmpstring)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface description too long"); goto error; } /* Retrieve adapter description */ nread = sock_recv(sockctrl, tmpstring, findalldevs_if.desclen, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE); if (nread == -1) goto error; totread += nread; tmpstring[findalldevs_if.desclen] = 0; pcap_snprintf(tmpstring2, sizeof(tmpstring2) - 1, "%s '%s' %s %s", PCAP_TEXT_SOURCE_ADAPTER, tmpstring, PCAP_TEXT_SOURCE_ON_REMOTE_HOST, host); stringlen = strlen(tmpstring2); dev->description = (char *)malloc(stringlen + 1); if (dev->description == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); goto error; } /* Copy the new device description into the correct memory location */ strlcpy(dev->description, tmpstring2, stringlen + 1); } dev->flags = ntohl(findalldevs_if.flags); naddr = 0; addr = NULL; /* loop until all addresses have been received */ for (j = 0; j < findalldevs_if.naddr; j++) { struct rpcap_findalldevs_ifaddr ifaddr; /* Retrieve the interface addresses */ nread = sock_recv(sockctrl, (char *)&ifaddr, sizeof(struct rpcap_findalldevs_ifaddr), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE); if (nread == -1) goto error; totread += nread; /* * WARNING libpcap bug: the address listing is * available only for AF_INET. * * XXX - IPv6? */ if (ntohs(ifaddr.addr.ss_family) == AF_INET) { if (addr == NULL) { dev->addresses = (struct pcap_addr *) malloc(sizeof(struct pcap_addr)); addr = dev->addresses; } else { addr->next = (struct pcap_addr *) malloc(sizeof(struct pcap_addr)); addr = addr->next; } naddr++; if (addr == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); goto error; } addr->next = NULL; if (rpcap_deseraddr((struct sockaddr_storage *) &ifaddr.addr, (struct sockaddr_storage **) &addr->addr, errbuf) == -1) goto error; if (rpcap_deseraddr((struct sockaddr_storage *) &ifaddr.netmask, (struct sockaddr_storage **) &addr->netmask, errbuf) == -1) goto error; if (rpcap_deseraddr((struct sockaddr_storage *) &ifaddr.broadaddr, (struct sockaddr_storage **) &addr->broadaddr, errbuf) == -1) goto error; if (rpcap_deseraddr((struct sockaddr_storage *) &ifaddr.dstaddr, (struct sockaddr_storage **) &addr->dstaddr, errbuf) == -1) goto error; if ((addr->addr == NULL) && (addr->netmask == NULL) && (addr->broadaddr == NULL) && (addr->dstaddr == NULL)) { free(addr); addr = NULL; if (naddr == 1) naddr = 0; /* the first item of the list had NULL addresses */ } } } } /* Checks if all the data has been read; if not, discard the data in excess */ if (totread != ntohl(header.plen)) { if (sock_discard(sockctrl, ntohl(header.plen) - totread, errbuf, PCAP_ERRBUF_SIZE) == 1) return -1; } /* Control connection has to be closed only in case the remote machine is in passive mode */ if (!active) { /* DO not send RPCAP_CLOSE, since we did not open a pcap_t; no need to free resources */ if (sock_close(sockctrl, errbuf, PCAP_ERRBUF_SIZE)) return -1; } /* To avoid inconsistencies in the number of sock_init() */ sock_cleanup(); return 0; error: /* * In case there has been an error, I don't want to overwrite it with a new one * if the following call fails. I want to return always the original error. * * Take care: this connection can already be closed when we try to close it. * This happens because a previous error in the rpcapd, which requested to * closed the connection. In that case, we already recognized that into the * rpspck_isheaderok() and we already acknowledged the closing. * In that sense, this call is useless here (however it is needed in case * the client generates the error). * * Checks if all the data has been read; if not, discard the data in excess */ if (totread != ntohl(header.plen)) { if (sock_discard(sockctrl, ntohl(header.plen) - totread, NULL, 0) == 1) return -1; } /* Control connection has to be closed only in case the remote machine is in passive mode */ if (!active) sock_close(sockctrl, NULL, 0); /* To avoid inconsistencies in the number of sock_init() */ sock_cleanup(); return -1; } int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf) { switch (type) { case PCAP_SRC_FILE: { strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE); if ((name) && (*name)) { strlcat(source, name, PCAP_BUF_SIZE); return 0; } else { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The file name cannot be NULL."); return -1; } } case PCAP_SRC_IFREMOTE: { strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE); if ((host) && (*host)) { if ((strcspn(host, "aAbBcCdDeEfFgGhHjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ")) == strlen(host)) { /* the host name does not contains alphabetic chars. So, it is a numeric address */ /* In this case we have to include it between square brackets */ strlcat(source, "[", PCAP_BUF_SIZE); strlcat(source, host, PCAP_BUF_SIZE); strlcat(source, "]", PCAP_BUF_SIZE); } else strlcat(source, host, PCAP_BUF_SIZE); if ((port) && (*port)) { strlcat(source, ":", PCAP_BUF_SIZE); strlcat(source, port, PCAP_BUF_SIZE); } strlcat(source, "/", PCAP_BUF_SIZE); } else { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host name cannot be NULL."); return -1; } if ((name) && (*name)) strlcat(source, name, PCAP_BUF_SIZE); return 0; } case PCAP_SRC_IFLOCAL: { strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE); if ((name) && (*name)) strlcat(source, name, PCAP_BUF_SIZE); return 0; } default: { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface type is not valid."); return -1; } } } int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf) { char *ptr; int ntoken; char tmpname[PCAP_BUF_SIZE]; char tmphost[PCAP_BUF_SIZE]; char tmpport[PCAP_BUF_SIZE]; int tmptype; /* Initialization stuff */ tmpname[0] = 0; tmphost[0] = 0; tmpport[0] = 0; if (host) *host = 0; if (port) *port = 0; if (name) *name = 0; /* Look for a 'rpcap://' identifier */ if ((ptr = strstr(source, PCAP_SRC_IF_STRING)) != NULL) { if (strlen(PCAP_SRC_IF_STRING) == strlen(source)) { /* The source identifier contains only the 'rpcap://' string. */ /* So, this is a local capture. */ *type = PCAP_SRC_IFLOCAL; return 0; } ptr += strlen(PCAP_SRC_IF_STRING); if (strchr(ptr, '[')) /* This is probably a numeric address */ { ntoken = sscanf(ptr, "[%[1234567890:.]]:%[^/]/%s", tmphost, tmpport, tmpname); if (ntoken == 1) /* probably the port is missing */ ntoken = sscanf(ptr, "[%[1234567890:.]]/%s", tmphost, tmpname); tmptype = PCAP_SRC_IFREMOTE; } else { ntoken = sscanf(ptr, "%[^/:]:%[^/]/%s", tmphost, tmpport, tmpname); if (ntoken == 1) { /* * This can be due to two reasons: * - we want a remote capture, but the network port is missing * - we want to do a local capture * To distinguish between the two, we look for the '/' char */ if (strchr(ptr, '/')) { /* We're on a remote capture */ sscanf(ptr, "%[^/]/%s", tmphost, tmpname); tmptype = PCAP_SRC_IFREMOTE; } else { /* We're on a local capture */ if (*ptr) strlcpy(tmpname, ptr, PCAP_BUF_SIZE); /* Clean the host name, since it is a remote capture */ /* NOTE: the host name has been assigned in the previous "ntoken= sscanf(...)" line */ tmphost[0] = 0; tmptype = PCAP_SRC_IFLOCAL; } } else tmptype = PCAP_SRC_IFREMOTE; } if (host) strlcpy(host, tmphost, PCAP_BUF_SIZE); if (port) strlcpy(port, tmpport, PCAP_BUF_SIZE); if (type) *type = tmptype; if (name) { /* * If the user wants the host name, but it cannot be located into the source string, return error * However, if the user is not interested in the interface name (e.g. if we're called by * pcap_findalldevs_ex(), which does not have interface name, do not return error */ if (tmpname[0]) { strlcpy(name, tmpname, PCAP_BUF_SIZE); } else { if (errbuf) pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface name has not been specified in the source string."); return -1; } } return 0; } /* Look for a 'file://' identifier */ if ((ptr = strstr(source, PCAP_SRC_FILE_STRING)) != NULL) { ptr += strlen(PCAP_SRC_FILE_STRING); if (*ptr) { if (name) strlcpy(name, ptr, PCAP_BUF_SIZE); if (type) *type = PCAP_SRC_FILE; return 0; } else { if (errbuf) pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The file name has not been specified in the source string."); return -1; } } /* Backward compatibility; the user didn't use the 'rpcap://, file://' specifiers */ if ((source) && (*source)) { if (name) strlcpy(name, source, PCAP_BUF_SIZE); if (type) *type = PCAP_SRC_IFLOCAL; return 0; } else { if (errbuf) pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface name has not been specified in the source string."); return -1; } }; pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf) { char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE], name[PCAP_BUF_SIZE]; int type; pcap_t *fp; int result; if (strlen(source) > PCAP_BUF_SIZE) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly."); return NULL; } /* determine the type of the source (file, local, remote) */ if (pcap_parsesrcstr(source, &type, host, port, name, errbuf) == -1) return NULL; switch (type) { case PCAP_SRC_FILE: fp = pcap_open_offline(name, errbuf); break; case PCAP_SRC_IFREMOTE: fp = pcap_create(source, errbuf); if (fp == NULL) { return NULL; } /* * Although we already have host, port and iface, we prefer TO PASS only 'pars' to the * pcap_open_remote() so that it has to call the pcap_parsesrcstr() again. * This is less optimized, but much clearer. */ result = pcap_opensource_remote(fp, auth); if (result != 0) { pcap_close(fp); return NULL; } struct pcap_md *md; /* structure used when doing a remote live capture */ md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win)); fp->snapshot = snaplen; fp->opt.timeout = read_timeout; md->rmt_flags = flags; break; case PCAP_SRC_IFLOCAL: fp = pcap_open_live(name, snaplen, (flags & PCAP_OPENFLAG_PROMISCUOUS), read_timeout, errbuf); #ifdef WIN32 /* * these flags are supported on Windows only */ if (fp != NULL && fp->adapter != NULL) { /* disable loopback capture if requested */ if (flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL) { if (!PacketSetLoopbackBehavior(fp->adapter, NPF_DISABLE_LOOPBACK)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unable to disable the capture of loopback packets."); pcap_close(fp); return NULL; } } /* set mintocopy to zero if requested */ if (flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS) { if (!PacketSetMinToCopy(fp->adapter, 0)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unable to set max responsiveness."); pcap_close(fp); return NULL; } } } #endif /* WIN32 */ break; default: strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE); return NULL; } return fp; } struct pcap_samp *pcap_setsampling(pcap_t *p) { struct pcap_md *md; /* structure used when doing a remote live capture */ md = (struct pcap_md *) ((u_char*)p->priv + sizeof(struct pcap_win)); return &(md->rmt_samp); } SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf) { /* socket-related variables */ struct addrinfo hints; /* temporary struct to keep settings needed to open the new socket */ struct addrinfo *addrinfo; /* keeps the addrinfo chain; required to open a new socket */ struct sockaddr_storage from; /* generic sockaddr_storage variable */ socklen_t fromlen; /* keeps the length of the sockaddr_storage variable */ SOCKET sockctrl; /* keeps the main socket identifier */ struct activehosts *temp, *prev; /* temp var needed to scan he host list chain */ *connectinghost = 0; /* just in case */ /* Prepare to open a new server socket */ memset(&hints, 0, sizeof(struct addrinfo)); /* WARNING Currently it supports only ONE socket family among ipv4 and IPv6 */ hints.ai_family = AF_INET; /* PF_UNSPEC to have both IPv4 and IPv6 server */ hints.ai_flags = AI_PASSIVE; /* Ready to a bind() socket */ hints.ai_socktype = SOCK_STREAM; /* Warning: this call can be the first one called by the user. */ /* For this reason, we have to initialize the WinSock support. */ if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) return -1; /* Do the work */ if ((port == NULL) || (port[0] == 0)) { if (sock_initaddress(address, RPCAP_DEFAULT_NETPORT_ACTIVE, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) { SOCK_ASSERT(errbuf, 1); return -2; } } else { if (sock_initaddress(address, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) { SOCK_ASSERT(errbuf, 1); return -2; } } if ((sockmain = sock_open(addrinfo, SOCKOPEN_SERVER, 1, errbuf, PCAP_ERRBUF_SIZE)) == -1) { SOCK_ASSERT(errbuf, 1); return -2; } /* Connection creation */ fromlen = sizeof(struct sockaddr_storage); sockctrl = accept(sockmain, (struct sockaddr *) &from, &fromlen); /* We're not using sock_close, since we do not want to send a shutdown */ /* (which is not allowed on a non-connected socket) */ closesocket(sockmain); sockmain = 0; if (sockctrl == -1) { sock_geterror("accept(): ", errbuf, PCAP_ERRBUF_SIZE); return -2; } /* Get the numeric for of the name of the connecting host */ if (getnameinfo((struct sockaddr *) &from, fromlen, connectinghost, RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST)) { sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE); rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL); sock_close(sockctrl, NULL, 0); return -1; } /* checks if the connecting host is among the ones allowed */ if (sock_check_hostlist((char *)hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0) { rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL); sock_close(sockctrl, NULL, 0); return -1; } /* Send authentication to the remote machine */ if (rpcap_sendauth(sockctrl, auth, errbuf) == -1) { rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL); sock_close(sockctrl, NULL, 0); return -3; } /* Checks that this host does not already have a cntrl connection in place */ /* Initialize pointers */ temp = activeHosts; prev = NULL; while (temp) { /* This host already has an active connection in place, so I don't have to update the host list */ if (sock_cmpaddr(&temp->host, &from) == 0) return sockctrl; prev = temp; temp = temp->next; } /* The host does not exist in the list; so I have to update the list */ if (prev) { prev->next = (struct activehosts *) malloc(sizeof(struct activehosts)); temp = prev->next; } else { activeHosts = (struct activehosts *) malloc(sizeof(struct activehosts)); temp = activeHosts; } if (temp == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL); sock_close(sockctrl, NULL, 0); return -1; } memcpy(&temp->host, &from, fromlen); temp->sockctrl = sockctrl; temp->next = NULL; return sockctrl; } int pcap_remoteact_close(const char *host, char *errbuf) { struct activehosts *temp, *prev; /* temp var needed to scan the host list chain */ struct addrinfo hints, *addrinfo, *ai_next; /* temp var needed to translate between hostname to its address */ int retval; temp = activeHosts; prev = NULL; /* retrieve the network address corresponding to 'host' */ addrinfo = NULL; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; retval = getaddrinfo(host, "0", &hints, &addrinfo); if (retval != 0) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval)); return -1; } while (temp) { ai_next = addrinfo; while (ai_next) { if (sock_cmpaddr(&temp->host, (struct sockaddr_storage *) ai_next->ai_addr) == 0) { struct rpcap_header header; /* Close this connection */ rpcap_createhdr(&header, RPCAP_MSG_CLOSE, 0, 0); /* I don't check for errors, since I'm going to close everything */ sock_send(temp->sockctrl, (char *)&header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE); if (sock_close(temp->sockctrl, errbuf, PCAP_ERRBUF_SIZE)) { /* To avoid inconsistencies in the number of sock_init() */ sock_cleanup(); return -1; } if (prev) prev->next = temp->next; else activeHosts = temp->next; freeaddrinfo(addrinfo); free(temp); /* To avoid inconsistencies in the number of sock_init() */ sock_cleanup(); return 0; } ai_next = ai_next->ai_next; } prev = temp; temp = temp->next; } if (addrinfo) freeaddrinfo(addrinfo); /* To avoid inconsistencies in the number of sock_init() */ sock_cleanup(); pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host you want to close the active connection is not known"); return -1; } void pcap_remoteact_cleanup(void) { /* Very dirty, but it works */ if (sockmain) { closesocket(sockmain); /* To avoid inconsistencies in the number of sock_init() */ sock_cleanup(); } } int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf) { struct activehosts *temp; /* temp var needed to scan the host list chain */ size_t len; char hoststr[RPCAP_HOSTLIST_SIZE + 1]; temp = activeHosts; len = 0; *hostlist = 0; while (temp) { /*int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen) */ /* Get the numeric form of the name of the connecting host */ if (sock_getascii_addrport((struct sockaddr_storage *) &temp->host, hoststr, RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST, errbuf, PCAP_ERRBUF_SIZE) != -1) /* if (getnameinfo( (struct sockaddr *) &temp->host, sizeof (struct sockaddr_storage), hoststr, */ /* RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST) ) */ { /* sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE); */ return -1; } len = len + strlen(hoststr) + 1 /* the separator */; if ((size < 0) || (len >= (size_t)size)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The string you provided is not able to keep " "the hostnames for all the active connections"); return -1; } strlcat(hostlist, hoststr, PCAP_ERRBUF_SIZE); hostlist[len - 1] = sep; hostlist[len] = 0; temp = temp->next; } return 0; } libpcap-1.8.1/atmuni31.h0000644000026300017510000000757013003771737013111 0ustar mcrmcr/* * Copyright (c) 1997 Yen Yen Lim and North Dakota State University * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Yen Yen Lim and North Dakota State University * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* Based on UNI3.1 standard by ATM Forum */ /* ATM traffic types based on VPI=0 and (the following VCI */ #define VCI_PPC 0x05 /* Point-to-point signal msg */ #define VCI_BCC 0x02 /* Broadcast signal msg */ #define VCI_OAMF4SC 0x03 /* Segment OAM F4 flow cell */ #define VCI_OAMF4EC 0x04 /* End-to-end OAM F4 flow cell */ #define VCI_METAC 0x01 /* Meta signal msg */ #define VCI_ILMIC 0x10 /* ILMI msg */ /* Q.2931 signalling messages */ #define CALL_PROCEED 0x02 /* call proceeding */ #define CONNECT 0x07 /* connect */ #define CONNECT_ACK 0x0f /* connect_ack */ #define SETUP 0x05 /* setup */ #define RELEASE 0x4d /* release */ #define RELEASE_DONE 0x5a /* release_done */ #define RESTART 0x46 /* restart */ #define RESTART_ACK 0x4e /* restart ack */ #define STATUS 0x7d /* status */ #define STATUS_ENQ 0x75 /* status ack */ #define ADD_PARTY 0x80 /* add party */ #define ADD_PARTY_ACK 0x81 /* add party ack */ #define ADD_PARTY_REJ 0x82 /* add party rej */ #define DROP_PARTY 0x83 /* drop party */ #define DROP_PARTY_ACK 0x84 /* drop party ack */ /* Information Element Parameters in the signalling messages */ #define CAUSE 0x08 /* cause */ #define ENDPT_REF 0x54 /* endpoint reference */ #define AAL_PARA 0x58 /* ATM adaptation layer parameters */ #define TRAFF_DESCRIP 0x59 /* atm traffic descriptors */ #define CONNECT_ID 0x5a /* connection identifier */ #define QOS_PARA 0x5c /* quality of service parameters */ #define B_HIGHER 0x5d /* broadband higher layer information */ #define B_BEARER 0x5e /* broadband bearer capability */ #define B_LOWER 0x5f /* broadband lower information */ #define CALLING_PARTY 0x6c /* calling party number */ #define CALLED_PARTY 0x70 /* called party nmber */ #define Q2931 0x09 /* Q.2931 signalling general messages format */ #define PROTO_POS 0 /* offset of protocol discriminator */ #define CALL_REF_POS 2 /* offset of call reference value */ #define MSG_TYPE_POS 5 /* offset of message type */ #define MSG_LEN_POS 7 /* offset of mesage length */ #define IE_BEGIN_POS 9 /* offset of first information element */ /* format of signalling messages */ #define TYPE_POS 0 #define LEN_POS 2 #define FIELD_BEGIN_POS 4 libpcap-1.8.1/pcap_version.h.in0000644000026300017510000000140513003771737014534 0ustar mcrmcr/* * We make the version string static, and return a pointer to it, rather * than exporting the version string directly. On at least some UNIXes, * if you import data from a shared library into an program, the data is * bound into the program binary, so if the string in the version of the * library with which the program was linked isn't the same as the * string in the version of the library with which the program is being * run, various undesirable things may happen (warnings, the string * being the one from the version of the library with which the program * was linked, or even weirder things, such as the string being the one * from the library but being truncated). */ static const char pcap_version_string[] = "libpcap version %%LIBPCAP_VERSION%%"; libpcap-1.8.1/pcap_get_selectable_fd.3pcap0000644000026300017510000001006513003771737016636 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_GET_SELECTABLE_FD 3PCAP "18 October 2014" .SH NAME pcap_get_selectable_fd \- get a file descriptor on which a select() can be done for a live capture .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_get_selectable_fd(pcap_t *p); .ft .fi .SH DESCRIPTION .B pcap_get_selectable_fd() returns, on UNIX, a file descriptor number for a file descriptor on which one can do a .BR select() , .BR poll() , or other such call to wait for it to be possible to read packets without blocking, if such a descriptor exists, or \-1, if no such descriptor exists. Some network devices opened with .B pcap_create() and .BR pcap_activate() , or with .BR pcap_open_live() , do not support .B select() or .B poll() (for example, regular network devices on FreeBSD 4.3 and 4.4, and Endace DAG devices), so \-1 is returned for those devices. .PP Note that a descriptor on which a read can be done without blocking may, on some platforms, not have any packets to read if the read timeout has expired. A call to .B pcap_dispatch() will return 0 in this case, but will not block. .PP Note that in: .IP FreeBSD prior to FreeBSD 4.6; .IP NetBSD prior to NetBSD 3.0; .IP OpenBSD prior to OpenBSD 2.4; .IP Mac OS X prior to Mac OS X 10.7; .PP .B select() and .B poll() do not work correctly on BPF devices; .B pcap_get_selectable_fd() will return a file descriptor on most of those versions (the exceptions being FreeBSD 4.3 and 4.4), but a simple .B select() or .B poll() will not indicate that the descriptor is readable until a full buffer's worth of packets is received, even if the read timeout expires before then. To work around this, an application that uses .B select() or .B poll() to wait for packets to arrive must put the .B pcap_t in non-blocking mode, and must arrange that the .B select() or .B poll() have a timeout less than or equal to the read timeout, and must try to read packets after that timeout expires, regardless of whether .B select() or .B poll() indicated that the file descriptor for the .B pcap_t is ready to be read or not. (That workaround will not work in FreeBSD 4.3 and later; however, in FreeBSD 4.6 and later, .B select() and .B poll() work correctly on BPF devices, so the workaround isn't necessary, although it does no harm.) .PP Note also that .B poll() doesn't work on character special files, including BPF devices, in Mac OS X 10.4 and 10.5, so, while .B select() can be used on the descriptor returned by .BR pcap_get_selectable_fd() , .B poll() cannot be used on it those versions of Mac OS X. Kqueues also don't work on that descriptor. .BR poll() , but not kqueues, work on that descriptor in Mac OS X releases prior to 10.4; .B poll() and kqueues work on that descriptor in Mac OS X 10.6 and later. .PP .B pcap_get_selectable_fd() is not available on Windows. .SH RETURN VALUE A selectable file descriptor is returned if one exists; otherwise, \-1 is returned. .SH SEE ALSO pcap(3PCAP), select(2), poll(2) libpcap-1.8.1/pcap-stdinc.h0000644000026300017510000001107013003771737013643 0ustar mcrmcr/* * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (C) 1999 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project 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 BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef pcap_stdinc_h #define pcap_stdinc_h /* * Avoids a compiler warning in case this was already defined * (someone defined _WINSOCKAPI_ when including 'windows.h', in order * to prevent it from including 'winsock.h') */ #ifdef _WINSOCKAPI_ #undef _WINSOCKAPI_ #endif #include #include #include #include #include #if defined(_MSC_VER) /* * MSVC. */ #if _MSC_VER >= 1800 /* * VS 2013 or newer; we have . */ #include #define u_int8_t uint8_t #define u_int16_t uint16_t #define u_int32_t uint32_t #define u_int64_t uint64_t #else /* * Earlier VS; we have to define this stuff ourselves. */ #ifndef HAVE_U_INT8_T typedef unsigned char u_int8_t; typedef signed char int8_t; #endif #ifndef HAVE_U_INT16_T typedef unsigned short u_int16_t; typedef signed short int16_t; #endif #ifndef HAVE_U_INT32_T typedef unsigned int u_int32_t; typedef signed int int32_t; #endif #ifndef HAVE_U_INT64_T #ifdef _MSC_EXTENSIONS typedef unsigned _int64 u_int64_t; typedef _int64 int64_t; #else /* _MSC_EXTENSIONS */ typedef unsigned long long u_int64_t; typedef long long int64_t; #endif #endif #endif #elif defined(__MINGW32__) #include #endif #endif /* pcap_stdinc_h */ libpcap-1.8.1/pcap-sita.h0000644000026300017510000000034013003771737013315 0ustar mcrmcr/* * pcap-sita.h: Packet capture interface for SITA WAN devices * * Authors: Fulko Hew (fulko.hew@sita.aero) (+1 905 6815570); */ extern int acn_parse_hosts_file(char *errbuf); extern int acn_findalldevs(char *errbuf); libpcap-1.8.1/ppp.h0000644000026300017510000000517013003771737012241 0ustar mcrmcr/* * Point to Point Protocol (PPP) RFC1331 * * Copyright 1989 by Carnegie Mellon. * * Permission to use, copy, modify, and distribute this program for any * purpose and without fee is hereby granted, provided that this copyright * and permission notice appear on all copies and supporting documentation, * the name of Carnegie Mellon not be used in advertising or publicity * pertaining to distribution of the program without specific prior * permission, and notice be given in supporting documentation that copying * and distribution is by permission of Carnegie Mellon and Stanford * University. Carnegie Mellon makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. */ #define PPP_ADDRESS 0xff /* The address byte value */ #define PPP_CONTROL 0x03 /* The control byte value */ #define PPP_PPPD_IN 0x00 /* non-standard for DLT_PPP_PPPD */ #define PPP_PPPD_OUT 0x01 /* non-standard for DLT_PPP_PPPD */ /* Protocol numbers */ #define PPP_IP 0x0021 /* Raw IP */ #define PPP_OSI 0x0023 /* OSI Network Layer */ #define PPP_NS 0x0025 /* Xerox NS IDP */ #define PPP_DECNET 0x0027 /* DECnet Phase IV */ #define PPP_APPLE 0x0029 /* Appletalk */ #define PPP_IPX 0x002b /* Novell IPX */ #define PPP_VJC 0x002d /* Van Jacobson Compressed TCP/IP */ #define PPP_VJNC 0x002f /* Van Jacobson Uncompressed TCP/IP */ #define PPP_BRPDU 0x0031 /* Bridging PDU */ #define PPP_STII 0x0033 /* Stream Protocol (ST-II) */ #define PPP_VINES 0x0035 /* Banyan Vines */ #define PPP_IPV6 0x0057 /* Internet Protocol version 6 */ #define PPP_HELLO 0x0201 /* 802.1d Hello Packets */ #define PPP_LUXCOM 0x0231 /* Luxcom */ #define PPP_SNS 0x0233 /* Sigma Network Systems */ #define PPP_MPLS_UCAST 0x0281 /* rfc 3032 */ #define PPP_MPLS_MCAST 0x0283 /* rfc 3022 */ #define PPP_IPCP 0x8021 /* IP Control Protocol */ #define PPP_OSICP 0x8023 /* OSI Network Layer Control Protocol */ #define PPP_NSCP 0x8025 /* Xerox NS IDP Control Protocol */ #define PPP_DECNETCP 0x8027 /* DECnet Control Protocol */ #define PPP_APPLECP 0x8029 /* Appletalk Control Protocol */ #define PPP_IPXCP 0x802b /* Novell IPX Control Protocol */ #define PPP_STIICP 0x8033 /* Strean Protocol Control Protocol */ #define PPP_VINESCP 0x8035 /* Banyan Vines Control Protocol */ #define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ #define PPP_MPLSCP 0x8281 /* rfc 3022 */ #define PPP_LCP 0xc021 /* Link Control Protocol */ #define PPP_PAP 0xc023 /* Password Authentication Protocol */ #define PPP_LQM 0xc025 /* Link Quality Monitoring */ #define PPP_CHAP 0xc223 /* Challenge Handshake Authentication Protocol */ libpcap-1.8.1/pcap.c0000644000026300017510000017041213003771737012362 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef _WIN32 #include #else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_BITYPES_H #include #endif #include #endif /* _WIN32 */ #include #include #include #if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__MINGW32__) #include #endif #include #include #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #ifdef MSDOS #include "pcap-dos.h" #endif #include "pcap-int.h" #ifdef HAVE_DAG_API #include "pcap-dag.h" #endif /* HAVE_DAG_API */ #ifdef HAVE_SEPTEL_API #include "pcap-septel.h" #endif /* HAVE_SEPTEL_API */ #ifdef HAVE_SNF_API #include "pcap-snf.h" #endif /* HAVE_SNF_API */ #ifdef HAVE_TC_API #include "pcap-tc.h" #endif /* HAVE_TC_API */ #ifdef PCAP_SUPPORT_USB #include "pcap-usb-linux.h" #endif #ifdef PCAP_SUPPORT_BT #include "pcap-bt-linux.h" #endif #ifdef PCAP_SUPPORT_BT_MONITOR #include "pcap-bt-monitor-linux.h" #endif #ifdef PCAP_SUPPORT_NETFILTER #include "pcap-netfilter-linux.h" #endif #ifdef PCAP_SUPPORT_DBUS #include "pcap-dbus.h" #endif static int pcap_not_initialized(pcap_t *pcap) { /* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */ (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), "This handle hasn't been activated yet"); /* this means 'not initialized' */ return (PCAP_ERROR_NOT_ACTIVATED); } #ifdef _WIN32 static void * pcap_not_initialized_ptr(pcap_t *pcap) { (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), "This handle hasn't been activated yet"); return (NULL); } static HANDLE pcap_getevent_not_initialized(pcap_t *pcap) { (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), "This handle hasn't been activated yet"); return (INVALID_HANDLE_VALUE); } static u_int pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue, int sync) { (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), "This handle hasn't been activated yet"); return (0); } static PAirpcapHandle pcap_get_airpcap_handle_not_initialized(pcap_t *pcap) { (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), "This handle hasn't been activated yet"); return (NULL); } #endif /* * Returns 1 if rfmon mode can be set on the pcap_t, 0 if it can't, * a PCAP_ERROR value on an error. */ int pcap_can_set_rfmon(pcap_t *p) { return (p->can_set_rfmon_op(p)); } /* * For systems where rfmon mode is never supported. */ static int pcap_cant_set_rfmon(pcap_t *p _U_) { return (0); } /* * Sets *tstamp_typesp to point to an array 1 or more supported time stamp * types; the return value is the number of supported time stamp types. * The list should be freed by a call to pcap_free_tstamp_types() when * you're done with it. * * A return value of 0 means "you don't get a choice of time stamp type", * in which case *tstamp_typesp is set to null. * * PCAP_ERROR is returned on error. */ int pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp) { if (p->tstamp_type_count == 0) { /* * We don't support multiple time stamp types. */ *tstamp_typesp = NULL; } else { *tstamp_typesp = (int*)calloc(sizeof(**tstamp_typesp), p->tstamp_type_count); if (*tstamp_typesp == NULL) { (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); return (PCAP_ERROR); } (void)memcpy(*tstamp_typesp, p->tstamp_type_list, sizeof(**tstamp_typesp) * p->tstamp_type_count); } return (p->tstamp_type_count); } /* * In Windows, you might have a library built with one version of the * C runtime library and an application built with another version of * the C runtime library, which means that the library might use one * version of malloc() and free() and the application might use another * version of malloc() and free(). If so, that means something * allocated by the library cannot be freed by the application, so we * need to have a pcap_free_tstamp_types() routine to free up the list * allocated by pcap_list_tstamp_types(), even though it's just a wrapper * around free(). */ void pcap_free_tstamp_types(int *tstamp_type_list) { free(tstamp_type_list); } /* * Default one-shot callback; overridden for capture types where the * packet data cannot be guaranteed to be available after the callback * returns, so that a copy must be made. */ void pcap_oneshot(u_char *user, const struct pcap_pkthdr *h, const u_char *pkt) { struct oneshot_userdata *sp = (struct oneshot_userdata *)user; *sp->hdr = *h; *sp->pkt = pkt; } const u_char * pcap_next(pcap_t *p, struct pcap_pkthdr *h) { struct oneshot_userdata s; const u_char *pkt; s.hdr = h; s.pkt = &pkt; s.pd = p; if (pcap_dispatch(p, 1, p->oneshot_callback, (u_char *)&s) <= 0) return (0); return (pkt); } int pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, const u_char **pkt_data) { struct oneshot_userdata s; s.hdr = &p->pcap_header; s.pkt = pkt_data; s.pd = p; /* Saves a pointer to the packet headers */ *pkt_header= &p->pcap_header; if (p->rfile != NULL) { int status; /* We are on an offline capture */ status = pcap_offline_read(p, 1, p->oneshot_callback, (u_char *)&s); /* * Return codes for pcap_offline_read() are: * - 0: EOF * - -1: error * - >1: OK * The first one ('0') conflicts with the return code of * 0 from pcap_read() meaning "no packets arrived before * the timeout expired", so we map it to -2 so you can * distinguish between an EOF from a savefile and a * "no packets arrived before the timeout expired, try * again" from a live capture. */ if (status == 0) return (-2); else return (status); } /* * Return codes for pcap_read() are: * - 0: timeout * - -1: error * - -2: loop was broken out of with pcap_breakloop() * - >1: OK * The first one ('0') conflicts with the return code of 0 from * pcap_offline_read() meaning "end of file". */ return (p->read_op(p, 1, p->oneshot_callback, (u_char *)&s)); } static struct capture_source_type { int (*findalldevs_op)(pcap_if_t **, char *); pcap_t *(*create_op)(const char *, char *, int *); } capture_source_types[] = { #ifdef HAVE_DAG_API { dag_findalldevs, dag_create }, #endif #ifdef HAVE_SEPTEL_API { septel_findalldevs, septel_create }, #endif #ifdef HAVE_SNF_API { snf_findalldevs, snf_create }, #endif #ifdef HAVE_TC_API { TcFindAllDevs, TcCreate }, #endif #ifdef PCAP_SUPPORT_BT { bt_findalldevs, bt_create }, #endif #ifdef PCAP_SUPPORT_BT_MONITOR { bt_monitor_findalldevs, bt_monitor_create }, #endif #ifdef PCAP_SUPPORT_USB { usb_findalldevs, usb_create }, #endif #ifdef PCAP_SUPPORT_NETFILTER { netfilter_findalldevs, netfilter_create }, #endif #ifdef PCAP_SUPPORT_DBUS { dbus_findalldevs, dbus_create }, #endif { NULL, NULL } }; /* * Get a list of all capture sources that are up and that we can open. * Returns -1 on error, 0 otherwise. * The list, as returned through "alldevsp", may be null if no interfaces * were up and could be opened. */ int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) { size_t i; /* * Find all the local network interfaces on which we * can capture. */ if (pcap_platform_finddevs(alldevsp, errbuf) == -1) return (-1); /* * Ask each of the non-local-network-interface capture * source types what interfaces they have. */ for (i = 0; capture_source_types[i].findalldevs_op != NULL; i++) { if (capture_source_types[i].findalldevs_op(alldevsp, errbuf) == -1) { /* * We had an error; free the list we've been * constructing. */ if (*alldevsp != NULL) { pcap_freealldevs(*alldevsp); *alldevsp = NULL; } return (-1); } } return (0); } pcap_t * pcap_create(const char *device, char *errbuf) { size_t i; int is_theirs; pcap_t *p; char *device_str; /* * A null device name is equivalent to the "any" device - * which might not be supported on this platform, but * this means that you'll get a "not supported" error * rather than, say, a crash when we try to dereference * the null pointer. */ if (device == NULL) device_str = strdup("any"); else { #ifdef _WIN32 /* * If the string appears to be little-endian UCS-2/UTF-16, * convert it to ASCII. * * XXX - to UTF-8 instead? Or report an error if any * character isn't ASCII? */ if (device[0] != '\0' && device[1] == '\0') { size_t length; length = wcslen((wchar_t *)device); device_str = (char *)malloc(length + 1); if (device_str == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (NULL); } pcap_snprintf(device_str, length + 1, "%ws", (const wchar_t *)device); } else #endif device_str = strdup(device); } if (device_str == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (NULL); } /* * Try each of the non-local-network-interface capture * source types until we find one that works for this * device or run out of types. */ for (i = 0; capture_source_types[i].create_op != NULL; i++) { is_theirs = 0; p = capture_source_types[i].create_op(device_str, errbuf, &is_theirs); if (is_theirs) { /* * The device name refers to a device of the * type in question; either it succeeded, * in which case p refers to a pcap_t to * later activate for the device, or it * failed, in which case p is null and we * should return that to report the failure * to create. */ if (p == NULL) { /* * We assume the caller filled in errbuf. */ free(device_str); return (NULL); } p->opt.device = device_str; return (p); } } /* * OK, try it as a regular network interface. */ p = pcap_create_interface(device_str, errbuf); if (p == NULL) { /* * We assume the caller filled in errbuf. */ free(device_str); return (NULL); } p->opt.device = device_str; return (p); } static void initialize_ops(pcap_t *p) { /* * Set operation pointers for operations that only work on * an activated pcap_t to point to a routine that returns * a "this isn't activated" error. */ p->read_op = (read_op_t)pcap_not_initialized; p->inject_op = (inject_op_t)pcap_not_initialized; p->setfilter_op = (setfilter_op_t)pcap_not_initialized; p->setdirection_op = (setdirection_op_t)pcap_not_initialized; p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized; p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized; p->setnonblock_op = (setnonblock_op_t)pcap_not_initialized; p->stats_op = (stats_op_t)pcap_not_initialized; #ifdef _WIN32 p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr; p->setbuff_op = (setbuff_op_t)pcap_not_initialized; p->setmode_op = (setmode_op_t)pcap_not_initialized; p->setmintocopy_op = (setmintocopy_op_t)pcap_not_initialized; p->getevent_op = pcap_getevent_not_initialized; p->oid_get_request_op = (oid_get_request_op_t)pcap_not_initialized; p->oid_set_request_op = (oid_set_request_op_t)pcap_not_initialized; p->sendqueue_transmit_op = pcap_sendqueue_transmit_not_initialized; p->setuserbuffer_op = (setuserbuffer_op_t)pcap_not_initialized; p->live_dump_op = (live_dump_op_t)pcap_not_initialized; p->live_dump_ended_op = (live_dump_ended_op_t)pcap_not_initialized; p->get_airpcap_handle_op = pcap_get_airpcap_handle_not_initialized; #endif /* * Default cleanup operation - implementations can override * this, but should call pcap_cleanup_live_common() after * doing their own additional cleanup. */ p->cleanup_op = pcap_cleanup_live_common; /* * In most cases, the standard one-shot callback can * be used for pcap_next()/pcap_next_ex(). */ p->oneshot_callback = pcap_oneshot; } static pcap_t * pcap_alloc_pcap_t(char *ebuf, size_t size) { char *chunk; pcap_t *p; /* * Allocate a chunk of memory big enough for a pcap_t * plus a structure following it of size "size". The * structure following it is a private data structure * for the routines that handle this pcap_t. */ chunk = malloc(sizeof (pcap_t) + size); if (chunk == NULL) { pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (NULL); } memset(chunk, 0, sizeof (pcap_t) + size); /* * Get a pointer to the pcap_t at the beginning. */ p = (pcap_t *)chunk; #ifndef _WIN32 p->fd = -1; /* not opened yet */ p->selectable_fd = -1; #endif if (size == 0) { /* No private data was requested. */ p->priv = NULL; } else { /* * Set the pointer to the private data; that's the structure * of size "size" following the pcap_t. */ p->priv = (void *)(chunk + sizeof (pcap_t)); } return (p); } pcap_t * pcap_create_common(char *ebuf, size_t size) { pcap_t *p; p = pcap_alloc_pcap_t(ebuf, size); if (p == NULL) return (NULL); /* * Default to "can't set rfmon mode"; if it's supported by * a platform, the create routine that called us can set * the op to its routine to check whether a particular * device supports it. */ p->can_set_rfmon_op = pcap_cant_set_rfmon; initialize_ops(p); /* put in some defaults*/ p->snapshot = MAXIMUM_SNAPLEN; /* max packet size */ p->opt.timeout = 0; /* no timeout specified */ p->opt.buffer_size = 0; /* use the platform's default */ p->opt.promisc = 0; p->opt.rfmon = 0; p->opt.immediate = 0; p->opt.tstamp_type = -1; /* default to not setting time stamp type */ p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO; /* * Start out with no BPF code generation flags set. */ p->bpf_codegen_flags = 0; return (p); } int pcap_check_activated(pcap_t *p) { if (p->activated) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform " " operation on activated capture"); return (-1); } return (0); } int pcap_set_snaplen(pcap_t *p, int snaplen) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); /* * Turn invalid values, or excessively large values, into * the maximum allowed value. * * If some application really *needs* a bigger snapshot * length, we should just increase MAXIMUM_SNAPLEN. */ if (snaplen <= 0 || snaplen > MAXIMUM_SNAPLEN) snaplen = MAXIMUM_SNAPLEN; p->snapshot = snaplen; return (0); } int pcap_set_promisc(pcap_t *p, int promisc) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); p->opt.promisc = promisc; return (0); } int pcap_set_rfmon(pcap_t *p, int rfmon) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); p->opt.rfmon = rfmon; return (0); } int pcap_set_timeout(pcap_t *p, int timeout_ms) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); p->opt.timeout = timeout_ms; return (0); } int pcap_set_tstamp_type(pcap_t *p, int tstamp_type) { int i; if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); /* * The argument should have been u_int, but that's too late * to change now - it's an API. */ if (tstamp_type < 0) return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP); /* * If p->tstamp_type_count is 0, we only support PCAP_TSTAMP_HOST; * the default time stamp type is PCAP_TSTAMP_HOST. */ if (p->tstamp_type_count == 0) { if (tstamp_type == PCAP_TSTAMP_HOST) { p->opt.tstamp_type = tstamp_type; return (0); } } else { /* * Check whether we claim to support this type of time stamp. */ for (i = 0; i < p->tstamp_type_count; i++) { if (p->tstamp_type_list[i] == (u_int)tstamp_type) { /* * Yes. */ p->opt.tstamp_type = tstamp_type; return (0); } } } /* * We don't support this type of time stamp. */ return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP); } int pcap_set_immediate_mode(pcap_t *p, int immediate) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); p->opt.immediate = immediate; return (0); } int pcap_set_buffer_size(pcap_t *p, int buffer_size) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); if (buffer_size <= 0) { /* * Silently ignore invalid values. */ return (0); } p->opt.buffer_size = buffer_size; return (0); } int pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision) { int i; if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); /* * The argument should have been u_int, but that's too late * to change now - it's an API. */ if (tstamp_precision < 0) return (PCAP_ERROR_TSTAMP_PRECISION_NOTSUP); /* * If p->tstamp_precision_count is 0, we only support setting * the time stamp precision to microsecond precision; every * pcap module *MUST* support microsecond precision, even if * it does so by converting the native precision to * microseconds. */ if (p->tstamp_precision_count == 0) { if (tstamp_precision == PCAP_TSTAMP_PRECISION_MICRO) { p->opt.tstamp_precision = tstamp_precision; return (0); } } else { /* * Check whether we claim to support this precision of * time stamp. */ for (i = 0; i < p->tstamp_precision_count; i++) { if (p->tstamp_precision_list[i] == (u_int)tstamp_precision) { /* * Yes. */ p->opt.tstamp_precision = tstamp_precision; return (0); } } } /* * We don't support this time stamp precision. */ return (PCAP_ERROR_TSTAMP_PRECISION_NOTSUP); } int pcap_get_tstamp_precision(pcap_t *p) { return (p->opt.tstamp_precision); } int pcap_activate(pcap_t *p) { int status; /* * Catch attempts to re-activate an already-activated * pcap_t; this should, for example, catch code that * calls pcap_open_live() followed by pcap_activate(), * as some code that showed up in a Stack Exchange * question did. */ if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); status = p->activate_op(p); if (status >= 0) p->activated = 1; else { if (p->errbuf[0] == '\0') { /* * No error message supplied by the activate routine; * for the benefit of programs that don't specially * handle errors other than PCAP_ERROR, return the * error message corresponding to the status. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_statustostr(status)); } /* * Undo any operation pointer setting, etc. done by * the activate operation. */ initialize_ops(p); } return (status); } pcap_t * pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *errbuf) { pcap_t *p; int status; p = pcap_create(device, errbuf); if (p == NULL) return (NULL); status = pcap_set_snaplen(p, snaplen); if (status < 0) goto fail; status = pcap_set_promisc(p, promisc); if (status < 0) goto fail; status = pcap_set_timeout(p, to_ms); if (status < 0) goto fail; /* * Mark this as opened with pcap_open_live(), so that, for * example, we show the full list of DLT_ values, rather * than just the ones that are compatible with capturing * when not in monitor mode. That allows existing applications * to work the way they used to work, but allows new applications * that know about the new open API to, for example, find out the * DLT_ values that they can select without changing whether * the adapter is in monitor mode or not. */ p->oldstyle = 1; status = pcap_activate(p); if (status < 0) goto fail; return (p); fail: if (status == PCAP_ERROR) pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device, p->errbuf); else if (status == PCAP_ERROR_NO_SUCH_DEVICE || status == PCAP_ERROR_PERM_DENIED || status == PCAP_ERROR_PROMISC_PERM_DENIED) pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", device, pcap_statustostr(status), p->errbuf); else pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device, pcap_statustostr(status)); pcap_close(p); return (NULL); } pcap_t * pcap_open_offline_common(char *ebuf, size_t size) { pcap_t *p; p = pcap_alloc_pcap_t(ebuf, size); if (p == NULL) return (NULL); p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO; return (p); } int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { return (p->read_op(p, cnt, callback, user)); } int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { register int n; for (;;) { if (p->rfile != NULL) { /* * 0 means EOF, so don't loop if we get 0. */ n = pcap_offline_read(p, cnt, callback, user); } else { /* * XXX keep reading until we get something * (or an error occurs) */ do { n = p->read_op(p, cnt, callback, user); } while (n == 0); } if (n <= 0) return (n); if (!PACKET_COUNT_IS_UNLIMITED(cnt)) { cnt -= n; if (cnt <= 0) return (0); } } } /* * Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate. */ void pcap_breakloop(pcap_t *p) { p->break_loop = 1; } int pcap_datalink(pcap_t *p) { if (!p->activated) return (PCAP_ERROR_NOT_ACTIVATED); return (p->linktype); } int pcap_datalink_ext(pcap_t *p) { if (!p->activated) return (PCAP_ERROR_NOT_ACTIVATED); return (p->linktype_ext); } int pcap_list_datalinks(pcap_t *p, int **dlt_buffer) { if (!p->activated) return (PCAP_ERROR_NOT_ACTIVATED); if (p->dlt_count == 0) { /* * We couldn't fetch the list of DLTs, which means * this platform doesn't support changing the * DLT for an interface. Return a list of DLTs * containing only the DLT this device supports. */ *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer)); if (*dlt_buffer == NULL) { (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); return (PCAP_ERROR); } **dlt_buffer = p->linktype; return (1); } else { *dlt_buffer = (int*)calloc(sizeof(**dlt_buffer), p->dlt_count); if (*dlt_buffer == NULL) { (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); return (PCAP_ERROR); } (void)memcpy(*dlt_buffer, p->dlt_list, sizeof(**dlt_buffer) * p->dlt_count); return (p->dlt_count); } } /* * In Windows, you might have a library built with one version of the * C runtime library and an application built with another version of * the C runtime library, which means that the library might use one * version of malloc() and free() and the application might use another * version of malloc() and free(). If so, that means something * allocated by the library cannot be freed by the application, so we * need to have a pcap_free_datalinks() routine to free up the list * allocated by pcap_list_datalinks(), even though it's just a wrapper * around free(). */ void pcap_free_datalinks(int *dlt_list) { free(dlt_list); } int pcap_set_datalink(pcap_t *p, int dlt) { int i; const char *dlt_name; if (dlt < 0) goto unsupported; if (p->dlt_count == 0 || p->set_datalink_op == NULL) { /* * We couldn't fetch the list of DLTs, or we don't * have a "set datalink" operation, which means * this platform doesn't support changing the * DLT for an interface. Check whether the new * DLT is the one this interface supports. */ if (p->linktype != dlt) goto unsupported; /* * It is, so there's nothing we need to do here. */ return (0); } for (i = 0; i < p->dlt_count; i++) if (p->dlt_list[i] == (u_int)dlt) break; if (i >= p->dlt_count) goto unsupported; if (p->dlt_count == 2 && p->dlt_list[0] == DLT_EN10MB && dlt == DLT_DOCSIS) { /* * This is presumably an Ethernet device, as the first * link-layer type it offers is DLT_EN10MB, and the only * other type it offers is DLT_DOCSIS. That means that * we can't tell the driver to supply DOCSIS link-layer * headers - we're just pretending that's what we're * getting, as, presumably, we're capturing on a dedicated * link to a Cisco Cable Modem Termination System, and * it's putting raw DOCSIS frames on the wire inside low-level * Ethernet framing. */ p->linktype = dlt; return (0); } if (p->set_datalink_op(p, dlt) == -1) return (-1); p->linktype = dlt; return (0); unsupported: dlt_name = pcap_datalink_val_to_name(dlt); if (dlt_name != NULL) { (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "%s is not one of the DLTs supported by this device", dlt_name); } else { (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "DLT %d is not one of the DLTs supported by this device", dlt); } return (-1); } /* * This array is designed for mapping upper and lower case letter * together for a case independent comparison. The mappings are * based upon ascii character sequences. */ static const u_char charmap[] = { (u_char)'\000', (u_char)'\001', (u_char)'\002', (u_char)'\003', (u_char)'\004', (u_char)'\005', (u_char)'\006', (u_char)'\007', (u_char)'\010', (u_char)'\011', (u_char)'\012', (u_char)'\013', (u_char)'\014', (u_char)'\015', (u_char)'\016', (u_char)'\017', (u_char)'\020', (u_char)'\021', (u_char)'\022', (u_char)'\023', (u_char)'\024', (u_char)'\025', (u_char)'\026', (u_char)'\027', (u_char)'\030', (u_char)'\031', (u_char)'\032', (u_char)'\033', (u_char)'\034', (u_char)'\035', (u_char)'\036', (u_char)'\037', (u_char)'\040', (u_char)'\041', (u_char)'\042', (u_char)'\043', (u_char)'\044', (u_char)'\045', (u_char)'\046', (u_char)'\047', (u_char)'\050', (u_char)'\051', (u_char)'\052', (u_char)'\053', (u_char)'\054', (u_char)'\055', (u_char)'\056', (u_char)'\057', (u_char)'\060', (u_char)'\061', (u_char)'\062', (u_char)'\063', (u_char)'\064', (u_char)'\065', (u_char)'\066', (u_char)'\067', (u_char)'\070', (u_char)'\071', (u_char)'\072', (u_char)'\073', (u_char)'\074', (u_char)'\075', (u_char)'\076', (u_char)'\077', (u_char)'\100', (u_char)'\141', (u_char)'\142', (u_char)'\143', (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147', (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153', (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157', (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163', (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167', (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\133', (u_char)'\134', (u_char)'\135', (u_char)'\136', (u_char)'\137', (u_char)'\140', (u_char)'\141', (u_char)'\142', (u_char)'\143', (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147', (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153', (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157', (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163', (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167', (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\173', (u_char)'\174', (u_char)'\175', (u_char)'\176', (u_char)'\177', (u_char)'\200', (u_char)'\201', (u_char)'\202', (u_char)'\203', (u_char)'\204', (u_char)'\205', (u_char)'\206', (u_char)'\207', (u_char)'\210', (u_char)'\211', (u_char)'\212', (u_char)'\213', (u_char)'\214', (u_char)'\215', (u_char)'\216', (u_char)'\217', (u_char)'\220', (u_char)'\221', (u_char)'\222', (u_char)'\223', (u_char)'\224', (u_char)'\225', (u_char)'\226', (u_char)'\227', (u_char)'\230', (u_char)'\231', (u_char)'\232', (u_char)'\233', (u_char)'\234', (u_char)'\235', (u_char)'\236', (u_char)'\237', (u_char)'\240', (u_char)'\241', (u_char)'\242', (u_char)'\243', (u_char)'\244', (u_char)'\245', (u_char)'\246', (u_char)'\247', (u_char)'\250', (u_char)'\251', (u_char)'\252', (u_char)'\253', (u_char)'\254', (u_char)'\255', (u_char)'\256', (u_char)'\257', (u_char)'\260', (u_char)'\261', (u_char)'\262', (u_char)'\263', (u_char)'\264', (u_char)'\265', (u_char)'\266', (u_char)'\267', (u_char)'\270', (u_char)'\271', (u_char)'\272', (u_char)'\273', (u_char)'\274', (u_char)'\275', (u_char)'\276', (u_char)'\277', (u_char)'\300', (u_char)'\341', (u_char)'\342', (u_char)'\343', (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347', (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353', (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357', (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363', (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367', (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\333', (u_char)'\334', (u_char)'\335', (u_char)'\336', (u_char)'\337', (u_char)'\340', (u_char)'\341', (u_char)'\342', (u_char)'\343', (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347', (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353', (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357', (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363', (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367', (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\373', (u_char)'\374', (u_char)'\375', (u_char)'\376', (u_char)'\377', }; int pcap_strcasecmp(const char *s1, const char *s2) { register const u_char *cm = charmap, *us1 = (const u_char *)s1, *us2 = (const u_char *)s2; while (cm[*us1] == cm[*us2++]) if (*us1++ == '\0') return(0); return (cm[*us1] - cm[*--us2]); } struct dlt_choice { const char *name; const char *description; int dlt; }; #define DLT_CHOICE(code, description) { #code, description, DLT_ ## code } #define DLT_CHOICE_SENTINEL { NULL, NULL, 0 } static struct dlt_choice dlt_choices[] = { DLT_CHOICE(NULL, "BSD loopback"), DLT_CHOICE(EN10MB, "Ethernet"), DLT_CHOICE(IEEE802, "Token ring"), DLT_CHOICE(ARCNET, "BSD ARCNET"), DLT_CHOICE(SLIP, "SLIP"), DLT_CHOICE(PPP, "PPP"), DLT_CHOICE(FDDI, "FDDI"), DLT_CHOICE(ATM_RFC1483, "RFC 1483 LLC-encapsulated ATM"), DLT_CHOICE(RAW, "Raw IP"), DLT_CHOICE(SLIP_BSDOS, "BSD/OS SLIP"), DLT_CHOICE(PPP_BSDOS, "BSD/OS PPP"), DLT_CHOICE(ATM_CLIP, "Linux Classical IP-over-ATM"), DLT_CHOICE(PPP_SERIAL, "PPP over serial"), DLT_CHOICE(PPP_ETHER, "PPPoE"), DLT_CHOICE(SYMANTEC_FIREWALL, "Symantec Firewall"), DLT_CHOICE(C_HDLC, "Cisco HDLC"), DLT_CHOICE(IEEE802_11, "802.11"), DLT_CHOICE(FRELAY, "Frame Relay"), DLT_CHOICE(LOOP, "OpenBSD loopback"), DLT_CHOICE(ENC, "OpenBSD encapsulated IP"), DLT_CHOICE(LINUX_SLL, "Linux cooked"), DLT_CHOICE(LTALK, "Localtalk"), DLT_CHOICE(PFLOG, "OpenBSD pflog file"), DLT_CHOICE(PFSYNC, "Packet filter state syncing"), DLT_CHOICE(PRISM_HEADER, "802.11 plus Prism header"), DLT_CHOICE(IP_OVER_FC, "RFC 2625 IP-over-Fibre Channel"), DLT_CHOICE(SUNATM, "Sun raw ATM"), DLT_CHOICE(IEEE802_11_RADIO, "802.11 plus radiotap header"), DLT_CHOICE(ARCNET_LINUX, "Linux ARCNET"), DLT_CHOICE(JUNIPER_MLPPP, "Juniper Multi-Link PPP"), DLT_CHOICE(JUNIPER_MLFR, "Juniper Multi-Link Frame Relay"), DLT_CHOICE(JUNIPER_ES, "Juniper Encryption Services PIC"), DLT_CHOICE(JUNIPER_GGSN, "Juniper GGSN PIC"), DLT_CHOICE(JUNIPER_MFR, "Juniper FRF.16 Frame Relay"), DLT_CHOICE(JUNIPER_ATM2, "Juniper ATM2 PIC"), DLT_CHOICE(JUNIPER_SERVICES, "Juniper Advanced Services PIC"), DLT_CHOICE(JUNIPER_ATM1, "Juniper ATM1 PIC"), DLT_CHOICE(APPLE_IP_OVER_IEEE1394, "Apple IP-over-IEEE 1394"), DLT_CHOICE(MTP2_WITH_PHDR, "SS7 MTP2 with Pseudo-header"), DLT_CHOICE(MTP2, "SS7 MTP2"), DLT_CHOICE(MTP3, "SS7 MTP3"), DLT_CHOICE(SCCP, "SS7 SCCP"), DLT_CHOICE(DOCSIS, "DOCSIS"), DLT_CHOICE(LINUX_IRDA, "Linux IrDA"), DLT_CHOICE(IEEE802_11_RADIO_AVS, "802.11 plus AVS radio information header"), DLT_CHOICE(JUNIPER_MONITOR, "Juniper Passive Monitor PIC"), DLT_CHOICE(BACNET_MS_TP, "BACnet MS/TP"), DLT_CHOICE(PPP_PPPD, "PPP for pppd, with direction flag"), DLT_CHOICE(JUNIPER_PPPOE, "Juniper PPPoE"), DLT_CHOICE(JUNIPER_PPPOE_ATM, "Juniper PPPoE/ATM"), DLT_CHOICE(GPRS_LLC, "GPRS LLC"), DLT_CHOICE(GPF_T, "GPF-T"), DLT_CHOICE(GPF_F, "GPF-F"), DLT_CHOICE(JUNIPER_PIC_PEER, "Juniper PIC Peer"), DLT_CHOICE(ERF_ETH, "Ethernet with Endace ERF header"), DLT_CHOICE(ERF_POS, "Packet-over-SONET with Endace ERF header"), DLT_CHOICE(LINUX_LAPD, "Linux vISDN LAPD"), DLT_CHOICE(JUNIPER_ETHER, "Juniper Ethernet"), DLT_CHOICE(JUNIPER_PPP, "Juniper PPP"), DLT_CHOICE(JUNIPER_FRELAY, "Juniper Frame Relay"), DLT_CHOICE(JUNIPER_CHDLC, "Juniper C-HDLC"), DLT_CHOICE(MFR, "FRF.16 Frame Relay"), DLT_CHOICE(JUNIPER_VP, "Juniper Voice PIC"), DLT_CHOICE(A429, "Arinc 429"), DLT_CHOICE(A653_ICM, "Arinc 653 Interpartition Communication"), DLT_CHOICE(USB_FREEBSD, "USB with FreeBSD header"), DLT_CHOICE(BLUETOOTH_HCI_H4, "Bluetooth HCI UART transport layer"), DLT_CHOICE(IEEE802_16_MAC_CPS, "IEEE 802.16 MAC Common Part Sublayer"), DLT_CHOICE(USB_LINUX, "USB with Linux header"), DLT_CHOICE(CAN20B, "Controller Area Network (CAN) v. 2.0B"), DLT_CHOICE(IEEE802_15_4_LINUX, "IEEE 802.15.4 with Linux padding"), DLT_CHOICE(PPI, "Per-Packet Information"), DLT_CHOICE(IEEE802_16_MAC_CPS_RADIO, "IEEE 802.16 MAC Common Part Sublayer plus radiotap header"), DLT_CHOICE(JUNIPER_ISM, "Juniper Integrated Service Module"), DLT_CHOICE(IEEE802_15_4, "IEEE 802.15.4 with FCS"), DLT_CHOICE(SITA, "SITA pseudo-header"), DLT_CHOICE(ERF, "Endace ERF header"), DLT_CHOICE(RAIF1, "Ethernet with u10 Networks pseudo-header"), DLT_CHOICE(IPMB, "IPMB"), DLT_CHOICE(JUNIPER_ST, "Juniper Secure Tunnel"), DLT_CHOICE(BLUETOOTH_HCI_H4_WITH_PHDR, "Bluetooth HCI UART transport layer plus pseudo-header"), DLT_CHOICE(AX25_KISS, "AX.25 with KISS header"), DLT_CHOICE(IEEE802_15_4_NONASK_PHY, "IEEE 802.15.4 with non-ASK PHY data"), DLT_CHOICE(MPLS, "MPLS with label as link-layer header"), DLT_CHOICE(LINUX_EVDEV, "Linux evdev events"), DLT_CHOICE(USB_LINUX_MMAPPED, "USB with padded Linux header"), DLT_CHOICE(DECT, "DECT"), DLT_CHOICE(AOS, "AOS Space Data Link protocol"), DLT_CHOICE(WIHART, "Wireless HART"), DLT_CHOICE(FC_2, "Fibre Channel FC-2"), DLT_CHOICE(FC_2_WITH_FRAME_DELIMS, "Fibre Channel FC-2 with frame delimiters"), DLT_CHOICE(IPNET, "Solaris ipnet"), DLT_CHOICE(CAN_SOCKETCAN, "CAN-bus with SocketCAN headers"), DLT_CHOICE(IPV4, "Raw IPv4"), DLT_CHOICE(IPV6, "Raw IPv6"), DLT_CHOICE(IEEE802_15_4_NOFCS, "IEEE 802.15.4 without FCS"), DLT_CHOICE(DBUS, "D-Bus"), DLT_CHOICE(JUNIPER_VS, "Juniper Virtual Server"), DLT_CHOICE(JUNIPER_SRX_E2E, "Juniper SRX E2E"), DLT_CHOICE(JUNIPER_FIBRECHANNEL, "Juniper Fibre Channel"), DLT_CHOICE(DVB_CI, "DVB-CI"), DLT_CHOICE(MUX27010, "MUX27010"), DLT_CHOICE(STANAG_5066_D_PDU, "STANAG 5066 D_PDUs"), DLT_CHOICE(JUNIPER_ATM_CEMIC, "Juniper ATM CEMIC"), DLT_CHOICE(NFLOG, "Linux netfilter log messages"), DLT_CHOICE(NETANALYZER, "Ethernet with Hilscher netANALYZER pseudo-header"), DLT_CHOICE(NETANALYZER_TRANSPARENT, "Ethernet with Hilscher netANALYZER pseudo-header and with preamble and SFD"), DLT_CHOICE(IPOIB, "RFC 4391 IP-over-Infiniband"), DLT_CHOICE(MPEG_2_TS, "MPEG-2 transport stream"), DLT_CHOICE(NG40, "ng40 protocol tester Iub/Iur"), DLT_CHOICE(NFC_LLCP, "NFC LLCP PDUs with pseudo-header"), DLT_CHOICE(INFINIBAND, "InfiniBand"), DLT_CHOICE(SCTP, "SCTP"), DLT_CHOICE(USBPCAP, "USB with USBPcap header"), DLT_CHOICE(RTAC_SERIAL, "Schweitzer Engineering Laboratories RTAC packets"), DLT_CHOICE(BLUETOOTH_LE_LL, "Bluetooth Low Energy air interface"), DLT_CHOICE(NETLINK, "Linux netlink"), DLT_CHOICE(BLUETOOTH_LINUX_MONITOR, "Bluetooth Linux Monitor"), DLT_CHOICE(BLUETOOTH_BREDR_BB, "Bluetooth Basic Rate/Enhanced Data Rate baseband packets"), DLT_CHOICE(BLUETOOTH_LE_LL_WITH_PHDR, "Bluetooth Low Energy air interface with pseudo-header"), DLT_CHOICE(PROFIBUS_DL, "PROFIBUS data link layer"), DLT_CHOICE(PKTAP, "Apple DLT_PKTAP"), DLT_CHOICE(EPON, "Ethernet with 802.3 Clause 65 EPON preamble"), DLT_CHOICE(IPMI_HPM_2, "IPMI trace packets"), DLT_CHOICE(ZWAVE_R1_R2, "Z-Wave RF profile R1 and R2 packets"), DLT_CHOICE(ZWAVE_R3, "Z-Wave RF profile R3 packets"), DLT_CHOICE(WATTSTOPPER_DLM, "WattStopper Digital Lighting Management (DLM) and Legrand Nitoo Open protocol"), DLT_CHOICE(ISO_14443, "ISO 14443 messages"), DLT_CHOICE(RDS, "IEC 62106 Radio Data System groups"), DLT_CHOICE_SENTINEL }; int pcap_datalink_name_to_val(const char *name) { int i; for (i = 0; dlt_choices[i].name != NULL; i++) { if (pcap_strcasecmp(dlt_choices[i].name, name) == 0) return (dlt_choices[i].dlt); } return (-1); } const char * pcap_datalink_val_to_name(int dlt) { int i; for (i = 0; dlt_choices[i].name != NULL; i++) { if (dlt_choices[i].dlt == dlt) return (dlt_choices[i].name); } return (NULL); } const char * pcap_datalink_val_to_description(int dlt) { int i; for (i = 0; dlt_choices[i].name != NULL; i++) { if (dlt_choices[i].dlt == dlt) return (dlt_choices[i].description); } return (NULL); } struct tstamp_type_choice { const char *name; const char *description; int type; }; static struct tstamp_type_choice tstamp_type_choices[] = { { "host", "Host", PCAP_TSTAMP_HOST }, { "host_lowprec", "Host, low precision", PCAP_TSTAMP_HOST_LOWPREC }, { "host_hiprec", "Host, high precision", PCAP_TSTAMP_HOST_HIPREC }, { "adapter", "Adapter", PCAP_TSTAMP_ADAPTER }, { "adapter_unsynced", "Adapter, not synced with system time", PCAP_TSTAMP_ADAPTER_UNSYNCED }, { NULL, NULL, 0 } }; int pcap_tstamp_type_name_to_val(const char *name) { int i; for (i = 0; tstamp_type_choices[i].name != NULL; i++) { if (pcap_strcasecmp(tstamp_type_choices[i].name, name) == 0) return (tstamp_type_choices[i].type); } return (PCAP_ERROR); } const char * pcap_tstamp_type_val_to_name(int tstamp_type) { int i; for (i = 0; tstamp_type_choices[i].name != NULL; i++) { if (tstamp_type_choices[i].type == tstamp_type) return (tstamp_type_choices[i].name); } return (NULL); } const char * pcap_tstamp_type_val_to_description(int tstamp_type) { int i; for (i = 0; tstamp_type_choices[i].name != NULL; i++) { if (tstamp_type_choices[i].type == tstamp_type) return (tstamp_type_choices[i].description); } return (NULL); } int pcap_snapshot(pcap_t *p) { if (!p->activated) return (PCAP_ERROR_NOT_ACTIVATED); return (p->snapshot); } int pcap_is_swapped(pcap_t *p) { if (!p->activated) return (PCAP_ERROR_NOT_ACTIVATED); return (p->swapped); } int pcap_major_version(pcap_t *p) { if (!p->activated) return (PCAP_ERROR_NOT_ACTIVATED); return (p->version_major); } int pcap_minor_version(pcap_t *p) { if (!p->activated) return (PCAP_ERROR_NOT_ACTIVATED); return (p->version_minor); } FILE * pcap_file(pcap_t *p) { return (p->rfile); } int pcap_fileno(pcap_t *p) { #ifndef _WIN32 return (p->fd); #else if (p->adapter != NULL) return ((int)(DWORD)p->adapter->hFile); else return (PCAP_ERROR); #endif } #if !defined(_WIN32) && !defined(MSDOS) int pcap_get_selectable_fd(pcap_t *p) { return (p->selectable_fd); } #endif void pcap_perror(pcap_t *p, const char *prefix) { fprintf(stderr, "%s: %s\n", prefix, p->errbuf); } char * pcap_geterr(pcap_t *p) { return (p->errbuf); } int pcap_getnonblock(pcap_t *p, char *errbuf) { int ret; ret = p->getnonblock_op(p, errbuf); if (ret == -1) { /* * In case somebody depended on the bug wherein * the error message was put into p->errbuf * by pcap_getnonblock_fd(). */ strlcpy(p->errbuf, errbuf, PCAP_ERRBUF_SIZE); } return (ret); } /* * Get the current non-blocking mode setting, under the assumption that * it's just the standard POSIX non-blocking flag. */ #if !defined(_WIN32) && !defined(MSDOS) int pcap_getnonblock_fd(pcap_t *p, char *errbuf) { int fdflags; fdflags = fcntl(p->fd, F_GETFL, 0); if (fdflags == -1) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", pcap_strerror(errno)); return (-1); } if (fdflags & O_NONBLOCK) return (1); else return (0); } #endif int pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf) { int ret; ret = p->setnonblock_op(p, nonblock, errbuf); if (ret == -1) { /* * In case somebody depended on the bug wherein * the error message was put into p->errbuf * by pcap_setnonblock_fd(). */ strlcpy(p->errbuf, errbuf, PCAP_ERRBUF_SIZE); } return (ret); } #if !defined(_WIN32) && !defined(MSDOS) /* * Set non-blocking mode, under the assumption that it's just the * standard POSIX non-blocking flag. (This can be called by the * per-platform non-blocking-mode routine if that routine also * needs to do some additional work.) */ int pcap_setnonblock_fd(pcap_t *p, int nonblock, char *errbuf) { int fdflags; fdflags = fcntl(p->fd, F_GETFL, 0); if (fdflags == -1) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", pcap_strerror(errno)); return (-1); } if (nonblock) fdflags |= O_NONBLOCK; else fdflags &= ~O_NONBLOCK; if (fcntl(p->fd, F_SETFL, fdflags) == -1) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s", pcap_strerror(errno)); return (-1); } return (0); } #endif #ifdef _WIN32 /* * Generate a string for a Win32-specific error (i.e. an error generated when * calling a Win32 API). * For errors occurred during standard C calls, we still use pcap_strerror() */ void pcap_win32_err_to_str(DWORD error, char *errbuf) { size_t errlen; char *p; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, PCAP_ERRBUF_SIZE, NULL); /* * "FormatMessage()" "helpfully" sticks CR/LF at the end of the * message. Get rid of it. */ errlen = strlen(errbuf); if (errlen >= 2) { errbuf[errlen - 1] = '\0'; errbuf[errlen - 2] = '\0'; } p = strchr(errbuf, '\0'); pcap_snprintf (p, PCAP_ERRBUF_SIZE+1-(p-errbuf), " (%lu)", error); } #endif /* * Generate error strings for PCAP_ERROR_ and PCAP_WARNING_ values. */ const char * pcap_statustostr(int errnum) { static char ebuf[15+10+1]; switch (errnum) { case PCAP_WARNING: return("Generic warning"); case PCAP_WARNING_TSTAMP_TYPE_NOTSUP: return ("That type of time stamp is not supported by that device"); case PCAP_WARNING_PROMISC_NOTSUP: return ("That device doesn't support promiscuous mode"); case PCAP_ERROR: return("Generic error"); case PCAP_ERROR_BREAK: return("Loop terminated by pcap_breakloop"); case PCAP_ERROR_NOT_ACTIVATED: return("The pcap_t has not been activated"); case PCAP_ERROR_ACTIVATED: return ("The setting can't be changed after the pcap_t is activated"); case PCAP_ERROR_NO_SUCH_DEVICE: return ("No such device exists"); case PCAP_ERROR_RFMON_NOTSUP: return ("That device doesn't support monitor mode"); case PCAP_ERROR_NOT_RFMON: return ("That operation is supported only in monitor mode"); case PCAP_ERROR_PERM_DENIED: return ("You don't have permission to capture on that device"); case PCAP_ERROR_IFACE_NOT_UP: return ("That device is not up"); case PCAP_ERROR_CANTSET_TSTAMP_TYPE: return ("That device doesn't support setting the time stamp type"); case PCAP_ERROR_PROMISC_PERM_DENIED: return ("You don't have permission to capture in promiscuous mode on that device"); case PCAP_ERROR_TSTAMP_PRECISION_NOTSUP: return ("That device doesn't support that time stamp precision"); } (void)pcap_snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum); return(ebuf); } /* * Not all systems have strerror(). */ const char * pcap_strerror(int errnum) { #ifdef HAVE_STRERROR #ifdef _WIN32 static char errbuf[PCAP_ERRBUF_SIZE]; errno_t errno; errno = strerror_s(errbuf, PCAP_ERRBUF_SIZE, errnum); if (errno != 0) /* errno = 0 if successful */ strlcpy(errbuf, "strerror_s() error", PCAP_ERRBUF_SIZE); return (errbuf); #else return (strerror(errnum)); #endif /* _WIN32 */ #else extern int sys_nerr; extern const char *const sys_errlist[]; static char errbuf[PCAP_ERRBUF_SIZE]; if ((unsigned int)errnum < sys_nerr) return ((char *)sys_errlist[errnum]); (void)pcap_snprintf(errbuf, sizeof errbuf, "Unknown error: %d", errnum); return (errbuf); #endif } int pcap_setfilter(pcap_t *p, struct bpf_program *fp) { return (p->setfilter_op(p, fp)); } /* * Set direction flag, which controls whether we accept only incoming * packets, only outgoing packets, or both. * Note that, depending on the platform, some or all direction arguments * might not be supported. */ int pcap_setdirection(pcap_t *p, pcap_direction_t d) { if (p->setdirection_op == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Setting direction is not implemented on this platform"); return (-1); } else return (p->setdirection_op(p, d)); } int pcap_stats(pcap_t *p, struct pcap_stat *ps) { return (p->stats_op(p, ps)); } static int pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Statistics aren't available from a pcap_open_dead pcap_t"); return (-1); } #ifdef _WIN32 struct pcap_stat * pcap_stats_ex(pcap_t *p, int *pcap_stat_size) { return (p->stats_ex_op(p, pcap_stat_size)); } int pcap_setbuff(pcap_t *p, int dim) { return (p->setbuff_op(p, dim)); } static int pcap_setbuff_dead(pcap_t *p, int dim) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The kernel buffer size cannot be set on a pcap_open_dead pcap_t"); return (-1); } int pcap_setmode(pcap_t *p, int mode) { return (p->setmode_op(p, mode)); } static int pcap_setmode_dead(pcap_t *p, int mode) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "impossible to set mode on a pcap_open_dead pcap_t"); return (-1); } int pcap_setmintocopy(pcap_t *p, int size) { return (p->setmintocopy_op(p, size)); } static int pcap_setmintocopy_dead(pcap_t *p, int size) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t"); return (-1); } HANDLE pcap_getevent(pcap_t *p) { return (p->getevent_op(p)); } static HANDLE pcap_getevent_dead(pcap_t *p) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "A pcap_open_dead pcap_t has no event handle"); return (INVALID_HANDLE_VALUE); } int pcap_oid_get_request(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp) { return (p->oid_get_request_op(p, oid, data, lenp)); } static int pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, size_t *lenp _U_) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "An OID get request cannot be performed on a pcap_open_dead pcap_t"); return (PCAP_ERROR); } int pcap_oid_set_request(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp) { return (p->oid_set_request_op(p, oid, data, lenp)); } static int pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_, size_t *lenp _U_) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "An OID set request cannot be performed on a pcap_open_dead pcap_t"); return (PCAP_ERROR); } pcap_send_queue * pcap_sendqueue_alloc(u_int memsize) { pcap_send_queue *tqueue; /* Allocate the queue */ tqueue = (pcap_send_queue *)malloc(sizeof(pcap_send_queue)); if (tqueue == NULL){ return (NULL); } /* Allocate the buffer */ tqueue->buffer = (char *)malloc(memsize); if (tqueue->buffer == NULL) { free(tqueue); return (NULL); } tqueue->maxlen = memsize; tqueue->len = 0; return (tqueue); } void pcap_sendqueue_destroy(pcap_send_queue *queue) { free(queue->buffer); free(queue); } int pcap_sendqueue_queue(pcap_send_queue *queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data) { if (queue->len + sizeof(struct pcap_pkthdr) + pkt_header->caplen > queue->maxlen){ return (-1); } /* Copy the pcap_pkthdr header*/ memcpy(queue->buffer + queue->len, pkt_header, sizeof(struct pcap_pkthdr)); queue->len += sizeof(struct pcap_pkthdr); /* copy the packet */ memcpy(queue->buffer + queue->len, pkt_data, pkt_header->caplen); queue->len += pkt_header->caplen; return (0); } u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync) { return (p->sendqueue_transmit_op(p, queue, sync)); } static u_int pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue, int sync) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Packets cannot be transmitted on a pcap_open_dead pcap_t"); return (0); } int pcap_setuserbuffer(pcap_t *p, int size) { return (p->setuserbuffer_op(p, size)); } static int pcap_setuserbuffer_dead(pcap_t *p, int size) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The user buffer cannot be set on a pcap_open_dead pcap_t"); return (-1); } int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks) { return (p->live_dump_op(p, filename, maxsize, maxpacks)); } static int pcap_live_dump_dead(pcap_t *p, char *filename, int maxsize, int maxpacks) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Live packet dumping cannot be performed on a pcap_open_dead pcap_t"); return (-1); } int pcap_live_dump_ended(pcap_t *p, int sync) { return (p->live_dump_ended_op(p, sync)); } static int pcap_live_dump_ended_dead(pcap_t *p, int sync) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Live packet dumping cannot be performed on a pcap_open_dead pcap_t"); return (-1); } PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p) { PAirpcapHandle handle; handle = p->get_airpcap_handle_op(p); if (handle == NULL) { (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf), "This isn't an AirPcap device"); } return (handle); } static PAirpcapHandle pcap_get_airpcap_handle_dead(pcap_t *p) { return (NULL); } #endif /* * On some platforms, we need to clean up promiscuous or monitor mode * when we close a device - and we want that to happen even if the * application just exits without explicitl closing devices. * On those platforms, we need to register a "close all the pcaps" * routine to be called when we exit, and need to maintain a list of * pcaps that need to be closed to clean up modes. * * XXX - not thread-safe. */ /* * List of pcaps on which we've done something that needs to be * cleaned up. * If there are any such pcaps, we arrange to call "pcap_close_all()" * when we exit, and have it close all of them. */ static struct pcap *pcaps_to_close; /* * TRUE if we've already called "atexit()" to cause "pcap_close_all()" to * be called on exit. */ static int did_atexit; static void pcap_close_all(void) { struct pcap *handle; while ((handle = pcaps_to_close) != NULL) pcap_close(handle); } int pcap_do_addexit(pcap_t *p) { /* * If we haven't already done so, arrange to have * "pcap_close_all()" called when we exit. */ if (!did_atexit) { if (atexit(pcap_close_all) != 0) { /* * "atexit()" failed; let our caller know. */ strlcpy(p->errbuf, "atexit failed", PCAP_ERRBUF_SIZE); return (0); } did_atexit = 1; } return (1); } void pcap_add_to_pcaps_to_close(pcap_t *p) { p->next = pcaps_to_close; pcaps_to_close = p; } void pcap_remove_from_pcaps_to_close(pcap_t *p) { pcap_t *pc, *prevpc; for (pc = pcaps_to_close, prevpc = NULL; pc != NULL; prevpc = pc, pc = pc->next) { if (pc == p) { /* * Found it. Remove it from the list. */ if (prevpc == NULL) { /* * It was at the head of the list. */ pcaps_to_close = pc->next; } else { /* * It was in the middle of the list. */ prevpc->next = pc->next; } break; } } } void pcap_cleanup_live_common(pcap_t *p) { if (p->buffer != NULL) { free(p->buffer); p->buffer = NULL; } if (p->dlt_list != NULL) { free(p->dlt_list); p->dlt_list = NULL; p->dlt_count = 0; } if (p->tstamp_type_list != NULL) { free(p->tstamp_type_list); p->tstamp_type_list = NULL; p->tstamp_type_count = 0; } if (p->tstamp_precision_list != NULL) { free(p->tstamp_precision_list); p->tstamp_precision_list = NULL; p->tstamp_precision_count = 0; } pcap_freecode(&p->fcode); #if !defined(_WIN32) && !defined(MSDOS) if (p->fd >= 0) { close(p->fd); p->fd = -1; } p->selectable_fd = -1; #endif } static void pcap_cleanup_dead(pcap_t *p _U_) { /* Nothing to do. */ } pcap_t * pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision) { pcap_t *p; switch (precision) { case PCAP_TSTAMP_PRECISION_MICRO: case PCAP_TSTAMP_PRECISION_NANO: break; default: return NULL; } p = malloc(sizeof(*p)); if (p == NULL) return NULL; memset (p, 0, sizeof(*p)); p->snapshot = snaplen; p->linktype = linktype; p->opt.tstamp_precision = precision; p->stats_op = pcap_stats_dead; #ifdef _WIN32 p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr; p->setbuff_op = pcap_setbuff_dead; p->setmode_op = pcap_setmode_dead; p->setmintocopy_op = pcap_setmintocopy_dead; p->getevent_op = pcap_getevent_dead; p->oid_get_request_op = pcap_oid_get_request_dead; p->oid_set_request_op = pcap_oid_set_request_dead; p->sendqueue_transmit_op = pcap_sendqueue_transmit_dead; p->setuserbuffer_op = pcap_setuserbuffer_dead; p->live_dump_op = pcap_live_dump_dead; p->live_dump_ended_op = pcap_live_dump_ended_dead; p->get_airpcap_handle_op = pcap_get_airpcap_handle_dead; #endif p->cleanup_op = pcap_cleanup_dead; /* * A "dead" pcap_t never requires special BPF code generation. */ p->bpf_codegen_flags = 0; p->activated = 1; return (p); } pcap_t * pcap_open_dead(int linktype, int snaplen) { return (pcap_open_dead_with_tstamp_precision(linktype, snaplen, PCAP_TSTAMP_PRECISION_MICRO)); } /* * API compatible with WinPcap's "send a packet" routine - returns -1 * on error, 0 otherwise. * * XXX - what if we get a short write? */ int pcap_sendpacket(pcap_t *p, const u_char *buf, int size) { if (p->inject_op(p, buf, size) == -1) return (-1); return (0); } /* * API compatible with OpenBSD's "send a packet" routine - returns -1 on * error, number of bytes written otherwise. */ int pcap_inject(pcap_t *p, const void *buf, size_t size) { return (p->inject_op(p, buf, size)); } void pcap_close(pcap_t *p) { if (p->opt.device != NULL) free(p->opt.device); p->cleanup_op(p); free(p); } /* * Given a BPF program, a pcap_pkthdr structure for a packet, and the raw * data for the packet, check whether the packet passes the filter. * Returns the return value of the filter program, which will be zero if * the packet doesn't pass and non-zero if the packet does pass. */ int pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h, const u_char *pkt) { const struct bpf_insn *fcode = fp->bf_insns; if (fcode != NULL) return (bpf_filter(fcode, pkt, h->len, h->caplen)); else return (0); } #include "pcap_version.h" #ifdef _WIN32 static char *full_pcap_version_string; #ifdef HAVE_VERSION_H /* * libpcap being built for Windows, as part of a WinPcap/Npcap source * tree. Include version.h from that source tree to get the WinPcap/Npcap * version. * * XXX - it'd be nice if we could somehow generate the WinPcap version number * when building WinPcap. (It'd be nice to do so for the packet.dll version * number as well.) */ #include "../../version.h" static const char wpcap_version_string[] = WINPCAP_VER_STRING; static const char pcap_version_string_fmt[] = WINPCAP_PRODUCT_NAME " version %s, based on %s"; static const char pcap_version_string_packet_dll_fmt[] = WINPCAP_PRODUCT_NAME " version %s (packet.dll version %s), based on %s"; const char * pcap_lib_version(void) { char *packet_version_string; size_t full_pcap_version_string_len; if (full_pcap_version_string == NULL) { /* * Generate the version string. */ packet_version_string = PacketGetVersion(); if (strcmp(wpcap_version_string, packet_version_string) == 0) { /* * WinPcap version string and packet.dll version * string are the same; just report the WinPcap * version. */ full_pcap_version_string_len = (sizeof pcap_version_string_fmt - 4) + strlen(wpcap_version_string) + strlen(pcap_version_string); full_pcap_version_string = malloc(full_pcap_version_string_len); if (full_pcap_version_string == NULL) return (NULL); pcap_snprintf(full_pcap_version_string, full_pcap_version_string_len, pcap_version_string_fmt, wpcap_version_string, pcap_version_string); } else { /* * WinPcap version string and packet.dll version * string are different; that shouldn't be the * case (the two libraries should come from the * same version of WinPcap), so we report both * versions. */ full_pcap_version_string_len = (sizeof pcap_version_string_packet_dll_fmt - 6) + strlen(wpcap_version_string) + strlen(packet_version_string) + strlen(pcap_version_string); full_pcap_version_string = malloc(full_pcap_version_string_len); if (full_pcap_version_string == NULL) return (NULL); pcap_snprintf(full_pcap_version_string, full_pcap_version_string_len, pcap_version_string_packet_dll_fmt, wpcap_version_string, packet_version_string, pcap_version_string); } } return (full_pcap_version_string); } #else /* HAVE_VERSION_H */ /* * libpcap being built for Windows, not as part of a WinPcap/Npcap source * tree. */ static const char pcap_version_string_packet_dll_fmt[] = "%s (packet.dll version %s)"; const char * pcap_lib_version(void) { char *packet_version_string; size_t full_pcap_version_string_len; if (full_pcap_version_string == NULL) { /* * Generate the version string. Report the packet.dll * version. */ packet_version_string = PacketGetVersion(); full_pcap_version_string_len = (sizeof pcap_version_string_packet_dll_fmt - 4) + strlen(pcap_version_string) + strlen(packet_version_string); full_pcap_version_string = malloc(full_pcap_version_string_len); if (full_pcap_version_string == NULL) return (NULL); pcap_snprintf(full_pcap_version_string, full_pcap_version_string_len, pcap_version_string_packet_dll_fmt, pcap_version_string, packet_version_string); } return (full_pcap_version_string); } #endif /* HAVE_VERSION_H */ #elif defined(MSDOS) static char *full_pcap_version_string; const char * pcap_lib_version (void) { char *packet_version_string; size_t full_pcap_version_string_len; static char dospfx[] = "DOS-"; if (full_pcap_version_string == NULL) { /* * Generate the version string. */ full_pcap_version_string_len = sizeof dospfx + strlen(pcap_version_string); full_pcap_version_string = malloc(full_pcap_version_string_len); if (full_pcap_version_string == NULL) return (NULL); strcpy(full_pcap_version_string, dospfx); strcat(full_pcap_version_string, pcap_version_string); } return (full_pcap_version_string); } #else /* UN*X */ const char * pcap_lib_version(void) { return (pcap_version_string); } #endif #ifdef YYDEBUG /* * Set the internal "debug printout" flag for the filter expression parser. * The code to print that stuff is present only if YYDEBUG is defined, so * the flag, and the routine to set it, are defined only if YYDEBUG is * defined. * * This is intended for libpcap developers, not for general use. * If you want to set these in a program, you'll have to declare this * routine yourself, with the appropriate DLL import attribute on Windows; * it's not declared in any header file, and won't be declared in any * header file provided by libpcap. */ PCAP_API void pcap_set_parser_debug(int value); PCAP_API_DEF void pcap_set_parser_debug(int value) { extern int pcap_debug; pcap_debug = value; } #endif #ifdef BDEBUG /* * Set the internal "debug printout" flag for the filter expression optimizer. * The code to print that stuff is present only if BDEBUG is defined, so * the flag, and the routine to set it, are defined only if BDEBUG is * defined. * * This is intended for libpcap developers, not for general use. * If you want to set these in a program, you'll have to declare this * routine yourself, with the appropriate DLL import attribute on Windows; * it's not declared in any header file, and won't be declared in any * header file provided by libpcap. */ PCAP_API void pcap_set_optimizer_debug(int value); PCAP_API_DEF void pcap_set_optimizer_debug(int value) { extern int pcap_optimizer_debug; pcap_optimizer_debug = value; } #endif libpcap-1.8.1/chmod_bpf0000755000026300017510000000137013003771737013136 0ustar mcrmcr#! /bin/sh # # Unfortunately, Mac OS X's devfs is based on the old FreeBSD # one, not the current one, so there's no way to configure it # to create BPF devices with particular owners or groups. # This startup item will make it owned by the admin group, # with permissions rw-rw----, so that anybody in the admin # group can use programs that capture or send raw packets. # # Change this as appropriate for your site, e.g. to make # it owned by a particular user without changing the permissions, # so only that user and the super-user can capture or send raw # packets, or give it the permissions rw-r-----, so that # only the super-user can send raw packets but anybody in the # admin group can capture packets. # chgrp admin /dev/bpf* chmod g+rw /dev/bpf* libpcap-1.8.1/CREDITS0000644000026300017510000002572713003771737012323 0ustar mcrmcrThis file lists people who have contributed to libpcap: The current maintainers: Bill Fenner Denis Ovsienko Fulvio Risso Guy Harris Hannes Gredler Michael Richardson Francois-Xavier Le Bail Additional people who have contributed patches: Akos Vandra Alan Bawden Albert Chin Alexander 'Leo' Bergolth Alexey Kuznetsov Alon Bar-Lev Andres Perera Andrew Brown Ani Sinha Antti Kantee Arien Vijn Arkadiusz Miskiewicz Armando L. Caro Jr. Assar Westerlund Bill Parker Brent Cook Brian Ginsbach Charles M. Hannum Chris G. Demetriou Chris Lightfoot Chris Maynard Chris Pepper Christian Bell Christian Peron Christian Svensson Daniele Orlandi Darren Lim Darren Reed David Clark David Kaelbling David Ward David Young Dean Gaudet dhruv Don Ebright Dug Song Dustin Spicuzza dzejarczech Edward Sheldrake Eric Anderson Erik de Castro Lopo Felix Obenhuber Florent Drouin Franz Schaefer frederich Fulko Hew Fumiyuki Shimizu Gabor Tatarka Garrett Cooper George Neville-Neil Gianluca Varenni Gilbert Hoyek Gisle Vanem Graeme Hewson Gregor Maier Greg Stark Greg Troxel Guillaume Pelat Gustavo Zacarias Hagen Paul Pfeifer Henri Doreau Hyung Sik Yoon Igor Khristophorov Jakub Zawadzki Jan-Philip Velders Jason R. Thorpe Javier Achirica Jean-Louis Charton Jean Tourrilhes Jefferson Ogata Jesper Dangaard Brouer Jesper Peterson Jesse Gross Jiri Slaby Joerg Mayer John Bankier Jon Lindgren Jon Smirl Jorge Boncompte [DTI2] Juergen Schoenwaelder Julien Moutinho Jung-uk Kim Kazushi Sugyo Klaus Klein Koryn Grant Kris Katterjohn Krzysztof Halasa Lorenzo Cavallaro Loris Degioanni Love Hörnquist-Ã…strand Luis MartinGarcia Maciej W. Rozycki Mansour Behabadi Marcus Felipe Pereira Mark C. Brown Mark Johnston Mark Pizzolato Markus Mayer Martin Husemann Márton Németh Matthew Luckie Max Laier Michal Labedzki Michal Sekletar Mike Frysinger Mike Kershaw Mike Wiacek Miroslav Lichvar Monroe Williams Nicolas Dade Niko Delarich N. Leiten Octavian Cerna Olaf Kirch Ollie Wild Onno van der Linden Paolo Abeni Patrick Marie Patrick McHardy Paul Mundt Pavel Kankovsky Pawel Pokrywka Peter Fales Peter Jeremy Peter Volkov Phil Wood Rafal Maszkowski Richard Stearn Rick Jones Robert Edmonds Roberto Mariani Romain Francoise Sagun Shakya Scott Barron Scott Gifford Scott Mcmillan Sebastian Krahmer Sebastien Roy Sepherosa Ziehau Shaun Clowes Solomon Peachy Stefan Hudson Stephen Donnelly Takashi Yamamoto Tanaka Shin-ya Tobias Poschwatta Tony Li Torsten Landschoff Uns Lider Uwe Girlich Wesley Shields Xianjie Zhang Xin Li Yen Yen Lim Yoann Vandoorselaere Yvan Vanhullebus The original LBL crew: Steve McCanne Craig Leres Van Jacobson Past maintainers: Jun-ichiro itojun Hagino Also see: http://www.wide.ad.jp/itojun-award/ libpcap-1.8.1/dlpisubs.h0000644000026300017510000000127613003771737013272 0ustar mcrmcr#ifndef dlpisubs_h #define dlpisubs_h #ifdef __cplusplus extern "C" { #endif /* * Private data for capturing on DLPI devices. */ struct pcap_dlpi { #ifdef HAVE_LIBDLPI dlpi_handle_t dlpi_hd; #endif /* HAVE_LIBDLPI */ #ifdef DL_HP_RAWDLS int send_fd; #endif /* DL_HP_RAWDLS */ struct pcap_stat stat; }; /* * Functions defined by dlpisubs.c. */ int pcap_stats_dlpi(pcap_t *, struct pcap_stat *); int pcap_process_pkts(pcap_t *, pcap_handler, u_char *, int, u_char *, int); int pcap_process_mactype(pcap_t *, u_int); #ifdef HAVE_SYS_BUFMOD_H int pcap_conf_bufmod(pcap_t *, int); #endif int pcap_alloc_databuf(pcap_t *); int strioctl(int, int, int, char *); #ifdef __cplusplus } #endif #endif libpcap-1.8.1/README.aix0000644000026300017510000000606413003771737012734 0ustar mcrmcrUsing BPF: (1) AIX 4.x's version of BPF is undocumented and somewhat unstandard; the current BPF support code includes changes that should work around that; it appears to compile and work on at least one AIX 4.3.3 machine. Note that the BPF driver and the "/dev/bpf" devices might not exist on your machine; AIX's tcpdump loads the driver and creates the devices if they don't already exist. Our libpcap should do the same, and the configure script should detect that it's on an AIX system and choose BPF even if the devices aren't there. Also note that tcpdump _binary_ compiled on AIX 4 may have a problem doing the initial loading of the BPF driver if copied to AIX 5 and run there (GH #52). tcpdump binary natively compiled on AIX 5 should not have this issue. (2) If libpcap doesn't compile on your machine when configured to use BPF, or if the workarounds fail to make it work correctly, you should send to tcpdump-workers@lists.tcpdump.org a detailed bug report (if the compile fails, send us the compile error messages; if it compiles but fails to work correctly, send us as detailed as possible a description of the symptoms, including indications of the network link-layer type being wrong or time stamps being wrong). If you fix the problems yourself, please submit a patch by forking the branch at https://github.com/the-tcpdump-group/libpcap/issues and issuing a pull request, so we can incorporate the fixes into the next release. If you don't fix the problems yourself, you can, as a workaround, make libpcap use DLPI instead of BPF. This can be done by specifying the flag: --with-pcap=dlpi to the "configure" script for libpcap. If you use DLPI: (1) It is a good idea to have the latest version of the DLPI driver on your system, since certain versions may be buggy and cause your AIX system to crash. DLPI is included in the fileset bos.rte.tty. I found that the DLPI driver that came with AIX 4.3.2 was buggy, and had to upgrade to bos.rte.tty 4.3.2.4: lslpp -l bos.rte.tty bos.rte.tty 4.3.2.4 COMMITTED Base TTY Support and Commands Updates for AIX filesets can be obtained from: ftp://service.software.ibm.com/aix/fixes/ These updates can be installed with the smit program. (2) After compiling libpcap, you need to make sure that the DLPI driver is loaded. Type: strload -q -d dlpi If the result is: dlpi: yes then the DLPI driver is loaded correctly. If it is: dlpi: no Then you need to type: strload -f /etc/dlpi.conf Check again with strload -q -d dlpi that the dlpi driver is loaded. Alternatively, you can uncomment the lines for DLPI in /etc/pse.conf and reboot the machine; this way DLPI will always be loaded when you boot your system. (3) There appears to be a problem in the DLPI code in some versions of AIX, causing a warning about DL_PROMISC_MULTI failing; this might be responsible for DLPI not being able to capture outgoing packets. libpcap-1.8.1/sf-pcap.h0000644000026300017510000000327413003771737012776 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. * * sf-pcap.h - libpcap-file-format-specific routines * Extraction/creation by Jeffrey Mogul, DECWRL * Modified by Steve McCanne, LBL. * * Used to save the received packet headers, after filtering, to * a file, and then read them later. * The first record in the file contains saved values for the machine * dependent values so we can print the dump file on any architecture. */ #ifndef sf_pcap_h #define sf_pcap_h extern pcap_t *pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, int *err); #endif libpcap-1.8.1/pcap_next_ex.3pcap0000644000026300017510000001153213003771737014675 0ustar mcrmcr.\" Copyright (c) 1994, 1996, 1997 .\" 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. .\" .TH PCAP_NEXT_EX 3PCAP "7 April 2014" .SH NAME pcap_next_ex, pcap_next \- read the next packet from a pcap_t .SH SYNOPSIS .nf .ft B #include .ft .LP .ft B int pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, .ti +8 const u_char **pkt_data); const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h); .ft .fi .SH DESCRIPTION .B pcap_next_ex() reads the next packet and returns a success/failure indication. If the packet was read without problems, the pointer pointed to by the .I pkt_header argument is set to point to the .I pcap_pkthdr struct for the packet, and the pointer pointed to by the .I pkt_data argument is set to point to the data in the packet. The .I struct pcap_pkthdr and the packet data are not to be freed by the caller, and are not guaranteed to be valid after the next call to .BR pcap_next_ex() , .BR pcap_next() , .BR pcap_loop() , or .BR pcap_dispatch() ; if the code needs them to remain valid, it must make a copy of them. .PP .B pcap_next() reads the next packet (by calling .B pcap_dispatch() with a .I cnt of 1) and returns a .I u_char pointer to the data in that packet. The packet data is not to be freed by the caller, and is not guaranteed to be valid after the next call to .BR pcap_next_ex() , .BR pcap_next() , .BR pcap_loop() , or .BR pcap_dispatch() ; if the code needs it to remain valid, it must make a copy of it. The .I pcap_pkthdr structure pointed to by .I h is filled in with the appropriate values for the packet. .PP The bytes of data from the packet begin with a link-layer header. The format of the link-layer header is indicated by the return value of the .B pcap_datalink() routine when handed the .B pcap_t value also passed to .B pcap_loop() or .BR pcap_dispatch() . .I http://www.tcpdump.org/linktypes.html lists the values .B pcap_datalink() can return and describes the packet formats that correspond to those values. The value it returns will be valid for all packets received unless and until .B pcap_set_datalink() is called; after a successful call to .BR pcap_set_datalink() , all subsequent packets will have a link-layer header of the type specified by the link-layer header type value passed to .BR pcap_set_datalink() . .PP Do .B NOT assume that the packets for a given capture or ``savefile`` will have any given link-layer header type, such as .B DLT_EN10MB for Ethernet. For example, the "any" device on Linux will have a link-layer header type of .B DLT_LINUX_SLL even if all devices on the system at the time the "any" device is opened have some other data link type, such as .B DLT_EN10MB for Ethernet. .SH RETURN VALUE .B pcap_next_ex() returns 1 if the packet was read without problems, 0 if packets are being read from a live capture and the timeout expired, \-1 if an error occurred while reading the packet, and \-2 if packets are being read from a ``savefile'' and there are no more packets to read from the savefile. If \-1 is returned, .B pcap_geterr() or .B pcap_perror() may be called with .I p as an argument to fetch or display the error text. .PP .B pcap_next() returns a pointer to the packet data on success, and returns .B NULL if an error occurred, or if no packets were read from a live capture (if, for example, they were discarded because they didn't pass the packet filter, or if, on platforms that support a read timeout that starts before any packets arrive, the timeout expires before any packets arrive, or if the file descriptor for the capture device is in non-blocking mode and no packets were available to be read), or if no more packets are available in a ``savefile.'' Unfortunately, there is no way to determine whether an error occurred or not. .SH SEE ALSO pcap(3PCAP), pcap_geterr(3PCAP), pcap_dispatch(3PCAP), pcap_datalink(3PCAP) libpcap-1.8.1/sf-pcap.c0000644000026300017510000006007513003771737012773 0ustar mcrmcr/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * 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. * * sf-pcap.c - libpcap-file-format-specific code from savefile.c * Extraction/creation by Jeffrey Mogul, DECWRL * Modified by Steve McCanne, LBL. * * Used to save the received packet headers, after filtering, to * a file, and then read them later. * The first record in the file contains saved values for the machine * dependent values so we can print the dump file on any architecture. */ #ifndef lint static const char rcsid[] _U_ = "@(#) $Header$ (LBL)"; #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef _WIN32 #include #else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_BITYPES_H #include #endif #include #endif /* _WIN32 */ #include #include #include #include #include #include "pcap-int.h" #include "pcap-common.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #include "sf-pcap.h" /* * Setting O_BINARY on DOS/Windows is a bit tricky */ #if defined(_WIN32) #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) #elif defined(MSDOS) #if defined(__HIGHC__) #define SET_BINMODE(f) setmode(f, O_BINARY) #else #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) #endif #endif /* * Standard libpcap format. */ #define TCPDUMP_MAGIC 0xa1b2c3d4 /* * Alexey Kuznetzov's modified libpcap format. */ #define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34 /* * Reserved for Francisco Mesquita * for another modified format. */ #define FMESQUITA_TCPDUMP_MAGIC 0xa1b234cd /* * Navtel Communcations' format, with nanosecond timestamps, * as per a request from Dumas Hwang . */ #define NAVTEL_TCPDUMP_MAGIC 0xa12b3c4d /* * Normal libpcap format, except for seconds/nanoseconds timestamps, * as per a request by Ulf Lamping */ #define NSEC_TCPDUMP_MAGIC 0xa1b23c4d /* * Mechanism for storing information about a capture in the upper * 6 bits of a linktype value in a capture file. * * LT_LINKTYPE_EXT(x) extracts the additional information. * * The rest of the bits are for a value describing the link-layer * value. LT_LINKTYPE(x) extracts that value. */ #define LT_LINKTYPE(x) ((x) & 0x03FFFFFF) #define LT_LINKTYPE_EXT(x) ((x) & 0xFC000000) static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap); /* * Private data for reading pcap savefiles. */ typedef enum { NOT_SWAPPED, SWAPPED, MAYBE_SWAPPED } swapped_type_t; typedef enum { PASS_THROUGH, SCALE_UP, SCALE_DOWN } tstamp_scale_type_t; struct pcap_sf { size_t hdrsize; swapped_type_t lengths_swapped; tstamp_scale_type_t scale_type; }; /* * Check whether this is a pcap savefile and, if it is, extract the * relevant information from the header. */ pcap_t * pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, int *err) { struct pcap_file_header hdr; size_t amt_read; pcap_t *p; int swapped = 0; struct pcap_sf *ps; /* * Assume no read errors. */ *err = 0; /* * Check whether the first 4 bytes of the file are the magic * number for a pcap savefile, or for a byte-swapped pcap * savefile. */ if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC && magic != NSEC_TCPDUMP_MAGIC) { magic = SWAPLONG(magic); if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC && magic != NSEC_TCPDUMP_MAGIC) return (NULL); /* nope */ swapped = 1; } /* * They are. Put the magic number in the header, and read * the rest of the header. */ hdr.magic = magic; amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1, sizeof(hdr) - sizeof(hdr.magic), fp); if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) { if (ferror(fp)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %lu file header bytes, only got %lu", (unsigned long)sizeof(hdr), (unsigned long)amt_read); } *err = 1; return (NULL); } /* * If it's a byte-swapped capture file, byte-swap the header. */ if (swapped) { hdr.version_major = SWAPSHORT(hdr.version_major); hdr.version_minor = SWAPSHORT(hdr.version_minor); hdr.thiszone = SWAPLONG(hdr.thiszone); hdr.sigfigs = SWAPLONG(hdr.sigfigs); hdr.snaplen = SWAPLONG(hdr.snaplen); hdr.linktype = SWAPLONG(hdr.linktype); } if (hdr.version_major < PCAP_VERSION_MAJOR) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "archaic pcap savefile format"); *err = 1; return (NULL); } /* * currently only versions 2.[0-4] are supported with * the exception of 543.0 for DG/UX tcpdump. */ if (! ((hdr.version_major == PCAP_VERSION_MAJOR && hdr.version_minor <= PCAP_VERSION_MINOR) || (hdr.version_major == 543 && hdr.version_minor == 0))) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unsupported pcap savefile version %u.%u", hdr.version_major, hdr.version_minor); *err = 1; return NULL; } if (hdr.snaplen > MAXIMUM_SNAPLEN) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "invalid file capture length %u, bigger than " "maximum of %u", hdr.snaplen, MAXIMUM_SNAPLEN); *err = 1; return NULL; } /* * OK, this is a good pcap file. * Allocate a pcap_t for it. */ p = pcap_open_offline_common(errbuf, sizeof (struct pcap_sf)); if (p == NULL) { /* Allocation failed. */ *err = 1; return (NULL); } p->swapped = swapped; p->version_major = hdr.version_major; p->version_minor = hdr.version_minor; p->tzoff = hdr.thiszone; p->snapshot = hdr.snaplen; p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype)); p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype); p->next_packet_op = pcap_next_packet; ps = p->priv; p->opt.tstamp_precision = precision; /* * Will we need to scale the timestamps to match what the * user wants? */ switch (precision) { case PCAP_TSTAMP_PRECISION_MICRO: if (magic == NSEC_TCPDUMP_MAGIC) { /* * The file has nanoseconds, the user * wants microseconds; scale the * precision down. */ ps->scale_type = SCALE_DOWN; } else { /* * The file has microseconds, the * user wants microseconds; nothing to do. */ ps->scale_type = PASS_THROUGH; } break; case PCAP_TSTAMP_PRECISION_NANO: if (magic == NSEC_TCPDUMP_MAGIC) { /* * The file has nanoseconds, the * user wants nanoseconds; nothing to do. */ ps->scale_type = PASS_THROUGH; } else { /* * The file has microoseconds, the user * wants nanoseconds; scale the * precision up. */ ps->scale_type = SCALE_UP; } break; default: pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown time stamp resolution %u", precision); free(p); *err = 1; return (NULL); } /* * We interchanged the caplen and len fields at version 2.3, * in order to match the bpf header layout. But unfortunately * some files were written with version 2.3 in their headers * but without the interchanged fields. * * In addition, DG/UX tcpdump writes out files with a version * number of 543.0, and with the caplen and len fields in the * pre-2.3 order. */ switch (hdr.version_major) { case 2: if (hdr.version_minor < 3) ps->lengths_swapped = SWAPPED; else if (hdr.version_minor == 3) ps->lengths_swapped = MAYBE_SWAPPED; else ps->lengths_swapped = NOT_SWAPPED; break; case 543: ps->lengths_swapped = SWAPPED; break; default: ps->lengths_swapped = NOT_SWAPPED; break; } if (magic == KUZNETZOV_TCPDUMP_MAGIC) { /* * XXX - the patch that's in some versions of libpcap * changes the packet header but not the magic number, * and some other versions with this magic number have * some extra debugging information in the packet header; * we'd have to use some hacks^H^H^H^H^Hheuristics to * detect those variants. * * Ethereal does that, but it does so by trying to read * the first two packets of the file with each of the * record header formats. That currently means it seeks * backwards and retries the reads, which doesn't work * on pipes. We want to be able to read from a pipe, so * that strategy won't work; we'd have to buffer some * data ourselves and read from that buffer in order to * make that work. */ ps->hdrsize = sizeof(struct pcap_sf_patched_pkthdr); if (p->linktype == DLT_EN10MB) { /* * This capture might have been done in raw mode * or cooked mode. * * If it was done in cooked mode, p->snapshot was * passed to recvfrom() as the buffer size, meaning * that the most packet data that would be copied * would be p->snapshot. However, a faked Ethernet * header would then have been added to it, so the * most data that would be in a packet in the file * would be p->snapshot + 14. * * We can't easily tell whether the capture was done * in raw mode or cooked mode, so we'll assume it was * cooked mode, and add 14 to the snapshot length. * That means that, for a raw capture, the snapshot * length will be misleading if you use it to figure * out why a capture doesn't have all the packet data, * but there's not much we can do to avoid that. */ p->snapshot += 14; } } else ps->hdrsize = sizeof(struct pcap_sf_pkthdr); /* * Allocate a buffer for the packet data. */ p->bufsize = p->snapshot; if (p->bufsize <= 0) { /* * Bogus snapshot length; use the maximum as a fallback. */ p->bufsize = MAXIMUM_SNAPLEN; } p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); free(p); *err = 1; return (NULL); } p->cleanup_op = sf_cleanup; return (p); } /* * Read and return the next packet from the savefile. Return the header * in hdr and a pointer to the contents in data. Return 0 on success, 1 * if there were no more packets, and -1 on an error. */ static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) { struct pcap_sf *ps = p->priv; struct pcap_sf_patched_pkthdr sf_hdr; FILE *fp = p->rfile; size_t amt_read; bpf_u_int32 t; /* * Read the packet header; the structure we use as a buffer * is the longer structure for files generated by the patched * libpcap, but if the file has the magic number for an * unpatched libpcap we only read as many bytes as the regular * header has. */ amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp); if (amt_read != ps->hdrsize) { if (ferror(fp)) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); return (-1); } else { if (amt_read != 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %lu header bytes, only got %lu", (unsigned long)ps->hdrsize, (unsigned long)amt_read); return (-1); } /* EOF */ return (1); } } if (p->swapped) { /* these were written in opposite byte order */ hdr->caplen = SWAPLONG(sf_hdr.caplen); hdr->len = SWAPLONG(sf_hdr.len); hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec); hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec); } else { hdr->caplen = sf_hdr.caplen; hdr->len = sf_hdr.len; hdr->ts.tv_sec = sf_hdr.ts.tv_sec; hdr->ts.tv_usec = sf_hdr.ts.tv_usec; } switch (ps->scale_type) { case PASS_THROUGH: /* * Just pass the time stamp through. */ break; case SCALE_UP: /* * File has microseconds, user wants nanoseconds; convert * it. */ hdr->ts.tv_usec = hdr->ts.tv_usec * 1000; break; case SCALE_DOWN: /* * File has nanoseconds, user wants microseconds; convert * it. */ hdr->ts.tv_usec = hdr->ts.tv_usec / 1000; break; } /* Swap the caplen and len fields, if necessary. */ switch (ps->lengths_swapped) { case NOT_SWAPPED: break; case MAYBE_SWAPPED: if (hdr->caplen <= hdr->len) { /* * The captured length is <= the actual length, * so presumably they weren't swapped. */ break; } /* FALLTHROUGH */ case SWAPPED: t = hdr->caplen; hdr->caplen = hdr->len; hdr->len = t; break; } if (hdr->caplen > p->bufsize) { /* * This can happen due to Solaris 2.3 systems tripping * over the BUFMOD problem and not setting the snapshot * correctly in the savefile header. * This can also happen with a corrupted savefile or a * savefile built/modified by a fuzz tester. * If the caplen isn't grossly wrong, try to salvage. */ size_t bytes_to_discard; size_t bytes_to_read, bytes_read; char discard_buf[4096]; if (hdr->caplen > MAXIMUM_SNAPLEN) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "invalid packet capture length %u, bigger than " "maximum of %u", hdr->caplen, MAXIMUM_SNAPLEN); return (-1); } /* * XXX - we don't grow the buffer here because some * program might assume that it will never get packets * bigger than the snapshot length; for example, it might * copy data from our buffer to a buffer of its own, * allocated based on the return value of pcap_snapshot(). * * Read the first p->bufsize bytes into the buffer. */ amt_read = fread(p->buffer, 1, p->bufsize, fp); if (amt_read != p->bufsize) { if (ferror(fp)) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { /* * Yes, this uses hdr->caplen; technically, * it's true, because we would try to read * and discard the rest of those bytes, and * that would fail because we got EOF before * the read finished. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %u captured bytes, only got %lu", hdr->caplen, (unsigned long)amt_read); } return (-1); } /* * Now read and discard what's left. */ bytes_to_discard = hdr->caplen - p->bufsize; bytes_read = amt_read; while (bytes_to_discard != 0) { bytes_to_read = bytes_to_discard; if (bytes_to_read > sizeof (discard_buf)) bytes_to_read = sizeof (discard_buf); amt_read = fread(discard_buf, 1, bytes_to_read, fp); bytes_read += amt_read; if (amt_read != bytes_to_read) { if (ferror(fp)) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %u captured bytes, only got %lu", hdr->caplen, (unsigned long)bytes_read); } return (-1); } bytes_to_discard -= amt_read; } /* * Adjust caplen accordingly, so we don't get confused later * as to how many bytes we have to play with. */ hdr->caplen = p->bufsize; } else { /* read the packet itself */ amt_read = fread(p->buffer, 1, hdr->caplen, fp); if (amt_read != hdr->caplen) { if (ferror(fp)) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %u captured bytes, only got %lu", hdr->caplen, (unsigned long)amt_read); } return (-1); } } *data = p->buffer; if (p->swapped) swap_pseudo_headers(p->linktype, hdr, *data); return (0); } static int sf_write_header(pcap_t *p, FILE *fp, int linktype, int thiszone, int snaplen) { struct pcap_file_header hdr; hdr.magic = p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? NSEC_TCPDUMP_MAGIC : TCPDUMP_MAGIC; hdr.version_major = PCAP_VERSION_MAJOR; hdr.version_minor = PCAP_VERSION_MINOR; hdr.thiszone = thiszone; hdr.snaplen = snaplen; hdr.sigfigs = 0; hdr.linktype = linktype; if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) return (-1); return (0); } /* * Output a packet to the initialized dump file. */ void pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) { register FILE *f; struct pcap_sf_pkthdr sf_hdr; f = (FILE *)user; sf_hdr.ts.tv_sec = h->ts.tv_sec; sf_hdr.ts.tv_usec = h->ts.tv_usec; sf_hdr.caplen = h->caplen; sf_hdr.len = h->len; /* XXX we should check the return status */ (void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f); (void)fwrite(sp, h->caplen, 1, f); } static pcap_dumper_t * pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) { #if defined(_WIN32) || defined(MSDOS) /* * If we're writing to the standard output, put it in binary * mode, as savefiles are binary files. * * Otherwise, we turn off buffering. * XXX - why? And why not on the standard output? */ if (f == stdout) SET_BINMODE(f); else setbuf(f, NULL); #endif if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", fname, pcap_strerror(errno)); if (f != stdout) (void)fclose(f); return (NULL); } return ((pcap_dumper_t *)f); } /* * Initialize so that sf_write() will output to the file named 'fname'. */ pcap_dumper_t * pcap_dump_open(pcap_t *p, const char *fname) { FILE *f; int linktype; /* * If this pcap_t hasn't been activated, it doesn't have a * link-layer type, so we can't use it. */ if (!p->activated) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: not-yet-activated pcap_t passed to pcap_dump_open", fname); return (NULL); } linktype = dlt_to_linktype(p->linktype); if (linktype == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: link-layer type %d isn't supported in savefiles", fname, p->linktype); return (NULL); } linktype |= p->linktype_ext; if (fname == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "A null pointer was supplied as the file name"); return NULL; } if (fname[0] == '-' && fname[1] == '\0') { f = stdout; fname = "standard output"; } else { #if !defined(_WIN32) && !defined(MSDOS) f = fopen(fname, "w"); #else f = fopen(fname, "wb"); #endif if (f == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, pcap_strerror(errno)); return (NULL); } } return (pcap_setup_dump(p, linktype, f, fname)); } /* * Initialize so that sf_write() will output to the given stream. */ pcap_dumper_t * pcap_dump_fopen(pcap_t *p, FILE *f) { int linktype; linktype = dlt_to_linktype(p->linktype); if (linktype == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "stream: link-layer type %d isn't supported in savefiles", p->linktype); return (NULL); } linktype |= p->linktype_ext; return (pcap_setup_dump(p, linktype, f, "stream")); } pcap_dumper_t * pcap_dump_open_append(pcap_t *p, const char *fname) { FILE *f; int linktype; size_t amt_read; struct pcap_file_header ph; linktype = dlt_to_linktype(p->linktype); if (linktype == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: link-layer type %d isn't supported in savefiles", fname, linktype); return (NULL); } if (fname == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "A null pointer was supplied as the file name"); return NULL; } if (fname[0] == '-' && fname[1] == '\0') return (pcap_setup_dump(p, linktype, stdout, "standard output")); #if !defined(_WIN32) && !defined(MSDOS) f = fopen(fname, "r+"); #else f = fopen(fname, "rb+"); #endif if (f == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, pcap_strerror(errno)); return (NULL); } /* * Try to read a pcap header. */ amt_read = fread(&ph, 1, sizeof (ph), f); if (amt_read != sizeof (ph)) { if (ferror(f)) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, pcap_strerror(errno)); fclose(f); return (NULL); } else if (feof(f) && amt_read > 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: truncated pcap file header", fname); fclose(f); return (NULL); } } #if defined(_WIN32) || defined(MSDOS) /* * We turn off buffering. * XXX - why? And why not on the standard output? */ setbuf(f, NULL); #endif /* * If a header is already present and: * * it's not for a pcap file of the appropriate resolution * and the right byte order for this machine; * * the link-layer header types don't match; * * the snapshot lengths don't match; * * return an error. */ if (amt_read > 0) { /* * A header is already present. * Do the checks. */ switch (ph.magic) { case TCPDUMP_MAGIC: if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: different time stamp precision, cannot append to file", fname); fclose(f); return (NULL); } break; case NSEC_TCPDUMP_MAGIC: if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: different time stamp precision, cannot append to file", fname); fclose(f); return (NULL); } break; case SWAPLONG(TCPDUMP_MAGIC): case SWAPLONG(NSEC_TCPDUMP_MAGIC): pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: different byte order, cannot append to file", fname); fclose(f); return (NULL); case KUZNETZOV_TCPDUMP_MAGIC: case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC): case NAVTEL_TCPDUMP_MAGIC: case SWAPLONG(NAVTEL_TCPDUMP_MAGIC): pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: not a pcap file to which we can append", fname); fclose(f); return (NULL); default: pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: not a pcap file", fname); fclose(f); return (NULL); } /* * Good version? */ if (ph.version_major != PCAP_VERSION_MAJOR || ph.version_minor != PCAP_VERSION_MINOR) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: version is %u.%u, cannot append to file", fname, ph.version_major, ph.version_minor); fclose(f); return (NULL); } if ((bpf_u_int32)linktype != ph.linktype) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: different linktype, cannot append to file", fname); fclose(f); return (NULL); } if ((bpf_u_int32)p->snapshot != ph.snaplen) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: different snaplen, cannot append to file", fname); fclose(f); return (NULL); } } else { /* * A header isn't present; attempt to write it. */ if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", fname, pcap_strerror(errno)); (void)fclose(f); return (NULL); } } /* * Start writing at the end of the file. */ if (fseek(f, 0, SEEK_END) == -1) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't seek to end of %s: %s", fname, pcap_strerror(errno)); (void)fclose(f); return (NULL); } return ((pcap_dumper_t *)f); } FILE * pcap_dump_file(pcap_dumper_t *p) { return ((FILE *)p); } long pcap_dump_ftell(pcap_dumper_t *p) { return (ftell((FILE *)p)); } int pcap_dump_flush(pcap_dumper_t *p) { if (fflush((FILE *)p) == EOF) return (-1); else return (0); } void pcap_dump_close(pcap_dumper_t *p) { #ifdef notyet if (ferror((FILE *)p)) return-an-error; /* XXX should check return from fclose() too */ #endif (void)fclose((FILE *)p); } libpcap-1.8.1/gen_version_header.sh0000755000026300017510000000056113003771737015455 0ustar mcrmcr#! /bin/sh print_version_string() { if grep GIT "$1" >/dev/null then read ver <"$1" echo $ver | tr -d '\012' date +_%Y_%m_%d else cat "$1" fi } if test $# != 3 then echo "Usage: gen_version_header.sh