libpcap read packet size - networking

I started to write an application which will read RTP/H.264 video packets from an existing .pcap file, I need to read the packet size.
I tried to use packet->len or header->len, but it never displays the right number of bytes for packets (I'm using wireshark to verify packet size - under Length column). How to do it?
This is part of my code:
while (packet = pcap_next(handle,&header)) {
u_char *pkt_ptr = (u_char *)packet;
struct ip *ip_hdr = (struct ip *)pkt_ptr; //point to an IP header structure
struct pcap_pkthdr *pkt_hdr =(struct pcap_pkthdr *)packet;
unsigned int packet_length = pkt_hdr->len;
unsigned int ip_length = ntohs(ip_hdr->ip_len);
printf("Packet # %i IP Header length: %d bytes, Packet length: %d bytes\n",pkt_counter,ip_length,packet_length);
Packet # 0 IP Header length: 180 bytes, Packet length: 104857664 bytes
Packet # 1 IP Header length: 52 bytes, Packet length: 104857600 bytes
Packet # 2 IP Header length: 100 bytes, Packet length: 104857600 bytes
Packet # 3 IP Header length: 100 bytes, Packet length: 104857664 bytes
Packet # 4 IP Header length: 52 bytes, Packet length: 104857600 bytes
Packet # 5 IP Header length: 100 bytes, Packet length: 104857600 bytes
Another option I tried is to use:
pkt_ptr-> I get:
read_pcapfile.c:67:43: error: request for member ‘len’ in something not a structure or union

while (packet = pcap_next(handle,&header)) {
u_char *pkt_ptr = (u_char *)packet;
Don't do that; you're throwing away the const, and you really should NOT be modifying what the return value of pcap_next() points to.
struct ip *ip_hdr = (struct ip *)pkt_ptr; //point to an IP header structure
That will point to an IP header structure ONLY if pcap_datalink(handle) returns DLT_RAW, which it probably will NOT do on most devices.
If, for example, pcap_datalink(handle) returns DLT_EN10MB, packet will point to an Ethernet header (the 10MB is historical - it's used for all Ethernet speeds other than the ancient historical 3MB experimental Ethernet at Xerox, which had a different header type).
See the list of link-layer header type values for a list of the possible DLT_ types.
struct pcap_pkthdr *pkt_hdr =(struct pcap_pkthdr *)packet;
That won't work, either. The struct pcap_pkthdr for the packet is in header.
unsigned int packet_length = pkt_hdr->len;
As per my earlier comment, that won't work. Use header.len instead.
(And bear in mind that, if a "snapshot length" shorter than the maximum packet size was specified in the pcap_open_live() call, or specified in a pcap_set_snaplen() call between the pcap_create() and pcap_activate() calls, header.caplen could be less than header.len, and only header.caplen bytes of the packet data will actually be available.)
unsigned int ip_length = ntohs(ip_hdr->ip_len);
And, as per my earlier comment, that probably won't work, either.

You should be using header.len.
unsigned int packet_length = header.len;

Related

Wireshark thinks scapy packet's raw data is DNS (malformed packet)

I'm trying to send a udp packet with scapy to the all the devices in my network with raw data: (hello everyone)
The packet looks like this:
packet = Ether(dst="ff:ff:ff:ff:ff:ff") / IP(dst="255.255.255.0") / UDP(sport=8118) / "hello everyone"
packet.show()
###[ Ethernet ]###
dst = ff:ff:ff:ff:ff:ff
src = (my mac address)
type = IPv4
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = udp
chksum = None
src = 192.168.0.105
dst = 255.255.255.0
\options \
###[ UDP ]###
sport = 8118
dport = domain
len = None
chksum = None
###[ Raw ]###
load = 'hello everyone'
When I send the packet (sendp(packet)), wireshark says this is a malformed DNS packet:
What is the problem?
I believe you're confusing Wireshark, due to you not specifying the destination port. If you don't specify a dport for UDP, it defaults to 53:
class UDP(Packet):
name = "UDP"
fields_desc = [ShortEnumField("sport", 53, UDP_SERVICES),
ShortEnumField("dport", 53, UDP_SERVICES),
ShortField("len", None),
XShortField("chksum", None), ]
Both ports actually do. 53 is for DNS though, so Wireshark is attempting to interpret your payload as DNS based on the port number.
Specify both sport and dport to ensure that your packet isn't misinterpreted as a DNS packet.

how to extract ip address from QueueDiscItem in ns3?

I'm new to NS3 and i was trying to extract ip address of a packet from QueueDiscItem,
when i have:
Ptr< QueueDiscItem > item initiated and call:
item->Print(std::cout);
the output i get is
"tos 0x0 DSCP Default ECN Not-ECT ttl 63 id 265 protocol 6 offset (bytes) 0 flags [none] length: 76 10.1.4.2 > 10.1.2.1 0x7fffc67ec880 Dst addr 02-06-ff:ff:ff:ff:ff:ff proto 2048 txq"
but when i call:
Ipv4Header header;
item->GetPacket()->PeekHeader(header);
header.Print(std::cout);
the output i get is
"tos 0x0 DSCP Default ECN Not-ECT ttl 0 id 0 protocol 0 offset (bytes) 0 flags [none] length: 20 102.102.102.102 > 102.102.102.102"
How to get the Header data
According to the list of TraceSources, the TraceSources associated with QueueDiscItems are for Queues. I'm guessing you were trying to attach to one of those TraceSources.
A QueueDiscItem encapsulates several things: a Ptr<Packet>, a MAC address, and several more things. Since you are using IPv4, the QueueDiscItem is actually an Ipv4QueueDiscItem (the latter is a subclass of the former). So, let's start by casting the QueueDiscItem to an Ipv4QueueDiscItem by
Ptr<const Ipv4QueueDiscItem> ipItem = DynamicCast<const Ipv4QueueDiscItem>(item);
Next, you need to know that at this point in the simulation, the Ipv4Header has not been added to the Ptr<Packet> yet. This is probably a design choice (that I don't understand). So, how can we get this information? Well, the Ipv4QueueDiscItem encapsulates the Ipv4Header, and at some point before passing the Ptr<Packet> to L2, the header is added to the packet. This Header can be retrieved by
const Ipv4Header ipHeader = ipItem->GetHeader();
So, now we have the Ipv4Header of the packet you're interested in. Now, we can safely get the address from the Ipv4QueueDiscItem by
ipHeader.GetSource();
ipHeader.GetDestination();
In summary, your TraceSource function should look something like this:
void
EnqueueTrace (Ptr<const QueueDiscItem> item) {
Ptr<const Ipv4QueueDiscItem> ipItem = DynamicCast<const Ipv4QueueDiscItem>(item);
const Ipv4Header ipHeader = ipItem->GetHeader();
NS_LOG_UNCOND("Packet received at " << Simulator::Now() << " going from " << ipHeader.GetSource() << " to " << ipHeader.GetDestination());
}
Why does item->Print(std::cout); work?
All of the above makes sense, but why does
item->Print(std::cout);
print the correct addresses? First, it is important to realize that here Print() is a function of the QueueDiscItem, not the Packet. If we go to the source of this function, we find that Print() just prints the Header if it has already been added.

libnetfilter_queue: Why can't I see the TCP payload of packets from nfq_get_payload?

I have a fairly basic user space firewall application. It receives data from libnetfilter_queue properly, we can see all the IP and TCP header information including source and destination IPs, ports, protocols, etc, but we don't get ANY of the TCP payload information...
The setup is pretty standard, I won't include it all but here are the highlights:
#define MAX_BUFFER_SIZE 65535
nfq_set_mode(qh, NFQNL_COPY_PACKET, MAX_BUFFER_SIZE)
So we are asking for the FULL PACKET back...
In the main thread we have:
rv = recv(fd, nfq_buffer, sizeof(nfq_buffer), 0);
printf("\nGot packet len: %d", rv);
if (rv > 0)
nfq_handle_packet(nfq_h, (char*)nfq_buffer, rv);
Here, on a standard HTTP call I will get a packet length of 140. But, in the callback handler the PACKET length is ALWAYS 64:
static int handle_packet(struct nfq_q_handle* qh, struct nfgenmsg* nfmsg, struct nfq_data* dat, void* data)
{
struct nfqnl_msg_packet_hdr* nfq_hdr = nfq_get_msg_packet_hdr(dat);
unsigned char* nf_packet;
int len = nfq_get_payload(dat,&nf_packet);
struct iphdr *iph = ((struct iphdr *) nf_packet);
iphdr_size = iph->ihl << 2;
if (iph->protocol == 6){
struct tcphdr *tcp = ((struct tcphdr *) (nf_packet + iphdr_size));
unsigned short tcphdr_size = (tcp->doff << 2);
printf("\nGot a packet!! len: %d iphdr: %d tcphdr: %d", len, iphdr_size, tcphdr_size);
}
}
In TCP, len is ALWAYS 64 (iphdr is 20, tcphdr is 44)... ALWAYS. I never get the TCP payload. What am I doing wrong???
Thanks to Joel for pointing out that problem was not in the C code, but in the iptables rules. There was a -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT rule prior to the NFQUEUE rule, so I was only getting the connection setup packets... whoops.

Playing AAC RTP stream using ffdshow

I am trying to play an RTP stream from using a custom network source filter and ffdshow audio decoder (ffdshow-tryout stable).
The mediatype that I set on my source output stream is MEDIASUBTYPE_RAW_AAC1. Here is what I am setting:
pmt->SetType(&MEDIATYPE_Audio);
pmt->SetSubtype(&MEDIASUBTYPE_RAW_AAC1);
pmt->SetFormatType(&FORMAT_WaveFormatEx);
BYTE *AACRAW;
DWORD dwLen = sizeof(WAVEFORMATEX) + 2; //2 bytes of audio config
AACRAW = (BYTE *)::CoTaskMemAlloc(dwLen);
memset(AACRAW, 0, dwLen);
WAVEFORMATEX wfx;
wfx.wFormatTag = WAVE_FORMAT_RAW_AAC1;
wfx.nChannels = 1;
wfx.nSamplesPerSec = 16000;
wfx.nAvgBytesPerSec = 8000;
wfx.nBlockAlign = 1;
wfx.wBitsPerSample= 0;
wfx.cbSize = 2;
memcpy(AACRAW, (void *)&wfx, sizeof(WAVEFORMATEX));
vector<unsigned char>extra;
extra.push_back(0x14);
extra.push_back(0x08);
memcpy(AACRAW + sizeof(WAVEFORMATEX), extra.data(), extra.size());
pmt->SetFormat(AACRAW, dwLen);
::CoTaskMemFree(AACRAW);
And then when I receive a rtp packet here is what I forward to the ffdshow filter:
DeliverRTPAAC(pRaw + 12 + 2 + 2, nBufSize - 12 - 2 - 2, pack.timestamp);
where pRaw is the pointer to the rtp packet. Each rtp packet that I receive contains one AU.
The filters connect but does not play audio. No error output from the AAC decoder as well.
The SDP parameters from the Axis camera are:
a=rtpmap:97 mpeg4-generic/16000/1
a=fmtp:97 streamtype=5; profile-level-id=15; mode=AAC-hbr; config=1408; sizeLength=13; indexLength=3; indexDeltaLength=3; profile=1; bitrate=64000;
Can somebody help me out please?
Probably the data you are receiving is wrapped in ADTS headers and you need to strip the ADTS header to supply the decoder with raw AAC.

Correlation between ICMP error messages and IP packets that generated them

I need to send a bunch of IP packets that I'm sure will trigger an ICMP TTL-expired error message. How exactly can I associate each error message with the packet that generated it? What field in the ICMP header is used for this?
Should I rather use some custom ID number in the original IP header, so that I can tell which error message corresponds to which packet? If so, which field is most suitable for this?
The body of ICMP TTL Expired messages must include the IP header of the original packet (which includes the source-port / destination-port) and 64 bits beyond the original header.
Based on timing and that header information, you can derive which packet triggered the TTL-expired message.
I am including a sample triggered by an NTP packet below...
See RFC 792 (Page 5) for more details.
ICMP TTL-Expired Message
Ethernet II, Src: JuniperN_c3:a0:00 (b0:c6:9a:c3:a0:00), Dst: 78:2b:cb:37:4c:7a (78:2b:cb:37:4c:7a)
Destination: 78:2b:cb:37:4c:7a (78:2b:cb:37:4c:7a)
Address: 78:2b:cb:37:4c:7a (78:2b:cb:37:4c:7a)
.... ...0 .... .... .... .... = IG bit: Individual address (unicast)
.... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
Source: JuniperN_c3:a0:00 (b0:c6:9a:c3:a0:00)
Address: JuniperN_c3:a0:00 (b0:c6:9a:c3:a0:00)
.... ...0 .... .... .... .... = IG bit: Individual address (unicast)
.... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
Type: IP (0x0800)
Internet Protocol, Src: 172.25.116.254 (172.25.116.254), Dst: 172.25.116.10 (172.25.116.10)
Version: 4
Header length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)
0000 00.. = Differentiated Services Codepoint: Default (0x00)
.... ..0. = ECN-Capable Transport (ECT): 0
.... ...0 = ECN-CE: 0
Total Length: 56
Identification: 0x86d7 (34519)
Flags: 0x02 (Don't Fragment)
0.. = Reserved bit: Not Set
.1. = Don't fragment: Set
..0 = More fragments: Not Set
Fragment offset: 0
Time to live: 255
Protocol: ICMP (0x01)
Header checksum: 0xb3b1 [correct]
[Good: True]
[Bad : False]
Source: 172.25.116.254 (172.25.116.254)
Destination: 172.25.116.10 (172.25.116.10)
Internet Control Message Protocol
Type: 11 (Time-to-live exceeded)
Code: 0 (Time to live exceeded in transit)
Checksum: 0x4613 [correct]
Internet Protocol, Src: 172.25.116.10 (172.25.116.10), Dst: 172.25.0.11 (172.25.0.11)
Version: 4
Header length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)
0000 00.. = Differentiated Services Codepoint: Default (0x00)
.... ..0. = ECN-Capable Transport (ECT): 0
.... ...0 = ECN-CE: 0
Total Length: 36
Identification: 0x0001 (1)
Flags: 0x00
0.. = Reserved bit: Not Set
.0. = Don't fragment: Not Set
..0 = More fragments: Not Set
Fragment offset: 0
Time to live: 0
[Expert Info (Note/Sequence): "Time To Live" only 0]
[Message: "Time To Live" only 0]
[Severity level: Note]
[Group: Sequence]
Protocol: UDP (0x11)
Header checksum: 0xee80 [correct]
[Good: True]
[Bad : False]
Source: 172.25.116.10 (172.25.116.10)
Destination: 172.25.0.11 (172.25.0.11)
User Datagram Protocol, Src Port: telindus (1728), Dst Port: ntp (123)
Source port: telindus (1728)
Destination port: ntp (123)
Length: 16
Checksum: 0xa7a1 [unchecked, not all data available]
[Good Checksum: False]
[Bad Checksum: False]

Resources