io.pkts.examples.core.CoreExample002 Maven / Gradle / Ivy
package io.pkts.examples.core;
import io.pkts.PacketHandler;
import io.pkts.Pcap;
import io.pkts.PcapOutputStream;
import io.pkts.packet.Packet;
import io.pkts.packet.UDPPacket;
import io.pkts.packet.sip.SipPacket;
import io.pkts.protocol.Protocol;
import io.pkts.sdp.RTPInfo;
import io.pkts.sdp.SDP;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* This is an example that takes a pcap and extracts outs a particular SIP call along
* with the potential RTP and writes it to a new pcap.
*
* This is very useful if you run a full tcpdump on your production machines and then
* would like to extract out individual calls. This is also possible to do with wireshark
* but it has a tendency to crash for larger files. Plus, who wants to do it manually anyway...
*
* @author [email protected]
*/
public class CoreExample002 {
public static void main(final String[] args) throws IOException {
// Step 1 - accept two inputs, first one being the pcap from which we will read
// and the second argument being the SIP Call-ID we are looking for.
final File inputFile = new File(args[0]);
final String callId = args[1];
// Step 2 - obtain a new Pcap instance by supplying an InputStream that points
// to a source that contains your captured traffic. Typically you may
// have stored that traffic in a file so there are a few convenience
// methods for those cases, such as just supplying the name of the
// file as shown below.
final Pcap pcap = Pcap.openStream(inputFile);
// Step 3 - Create a new Pcap output stream, to which we will be writing all
// those packets we wish to save.
final File outputFile = new File(inputFile.getParentFile(), callId + ".pcap");
final PcapOutputStream out = pcap.createOutputStream(new FileOutputStream(outputFile));
// Step 4 - Since we also want to save any potential RTP for this call
// we need to process the SDP in the SIP traffic and check
// which ip:port RTP will be coming from for this particular call.
// Later on, we will use this information to check if a particular UDP
// packet is to/from this IP:port and if so, we will save that packet.
final List rtpInfo = new ArrayList<>();
// Step 5 - Once you have obtained an instance, you want to start
// looping over the content of the pcap. Do this by calling
// the loop function and supply a PacketHandler, which is a
// simple interface with only a single method - nextPacket
pcap.loop(new PacketHandler() {
@Override
public boolean nextPacket(final Packet packet) throws IOException {
// Step 6 - In this example we assume SIP & RTP is both over UDP. For
// RTP that will most likely always be true (even though you
// can technically push it over TCP as well) but certainly not
// always true for SIP. However, this is just an example so we
// will keep this shortcut for illustrative purposes :-)
if (packet.hasProtocol(Protocol.UDP)) {
final UDPPacket udp = (UDPPacket) packet.getPacket(Protocol.UDP);
// Step 7 - If the packet is SIP and matches the call-id we are looking
// for then just save it to the output stream.
if (packet.hasProtocol(Protocol.SIP)) {
final SipPacket sip = (SipPacket) packet.getPacket(Protocol.SIP);
if (callId.equals(sip.getCallIDHeader().getValue().toString())) {
out.write(sip);
// Step 8 - if the message also has content (and we blindly assume it
// is SDP, which we obviously should check) then extract out
// the RTP information and save that so we later can check if
// a packet is to/from this IP:port
if (sip.hasContent()) {
final SDP sdp = (SDP) sip.getContent();
sdp.getRTPInfo().forEach(info -> rtpInfo.add(info));
}
}
} else if (rtpInfo.stream().filter(info -> (info.getAddress().equals(udp.getDestinationIP()) && info.getMediaPort() == udp.getDestinationPort())
|| (info.getAddress().equals(udp.getSourceIP()) && info.getMediaPort() == udp.getSourcePort())
).findFirst().isPresent()) {
// Step 9 - If the incoming UDP packet is from any known address
// as listed in an SDP then just save it.
out.write(packet);
}
}
return true;
}
});
out.flush();
out.close();
}
}