/* * Copyright 2010 NCHOVY * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.krakenapps.pcap.script; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeoutException; import org.krakenapps.api.Script; import org.krakenapps.api.ScriptArgument; import org.krakenapps.api.ScriptContext; import org.krakenapps.api.ScriptUsage; import org.krakenapps.pcap.Injectable; import org.krakenapps.pcap.decoder.ethernet.EthernetFrame; import org.krakenapps.pcap.decoder.ethernet.EthernetType; import org.krakenapps.pcap.decoder.ethernet.MacAddress; import org.krakenapps.pcap.decoder.ip.InternetProtocol; import org.krakenapps.pcap.decoder.ip.Ipv4Packet; import org.krakenapps.pcap.decoder.tcp.TcpPacket; import org.krakenapps.pcap.decoder.tcp.TcpSession; import org.krakenapps.pcap.live.PcapDevice; import org.krakenapps.pcap.live.PcapDeviceManager; import org.krakenapps.pcap.live.PcapDeviceMetadata; import org.krakenapps.pcap.live.PcapStreamManager; import org.krakenapps.pcap.live.PcapStat; import org.krakenapps.pcap.live.Promiscuous; import org.krakenapps.pcap.util.Arping; import org.krakenapps.pcap.util.Buffer; import org.krakenapps.pcap.util.PcapLiveRunner; import org.krakenapps.pcap.util.Ping; import org.krakenapps.pcap.util.Ping.PingResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author xeraph */ public class PcapScript implements Script { private Logger logger = LoggerFactory.getLogger(PcapScript.class); private PcapStreamManager streamManager; private ScriptContext context; public PcapScript(PcapStreamManager streamManager) { this.streamManager = streamManager; } @Override public void setScriptContext(ScriptContext context) { this.context = context; } @ScriptUsage(description = "", arguments = { @ScriptArgument(name = "host address", type = "string", description = "host address"), @ScriptArgument(name = "timeout", type = "integer", description = "timeout to millisecond", optional = true), @ScriptArgument(name = "ping count", type = "integer", description = "ping count", optional = true) }) public void ping(String[] args) { int timeout = 5000; if (args.length > 1) timeout = Integer.parseInt(args[1]); int seq = 4; if (args.length > 2) { seq = Integer.parseInt(args[2]); if (seq <= 0) seq = 4; } try { InetAddress target = InetAddress.getByName(args[0]); MacAddress dstMac = Arping.query(target, timeout); if (dstMac == null) { context.println("cannot find destination mac address."); return; } for (int i = 1; i <= seq; i++) { try { PingResponse resp = Ping.ping(dstMac, target, i % 65536, timeout); context.println(String.format("ping #%d: Reply from %s, bytes=%d, time%c%.1fs", i, resp.getPacket() .getSource().getHostAddress(), resp.getBytes(), (resp.getTime() == 1) ? '<' : '=', (double) (resp.getTime()) / 10)); try { Thread.sleep(1000); } catch (InterruptedException e) { } } catch (TimeoutException e) { context.println("timeout"); } } } catch (UnknownHostException e) { context.println("unknown host: " + args[0]); } catch (IOException e) { context.println("io error: " + e.getMessage()); } } public void streams(String[] args) { context.println("Live Streams"); context.println("-----------------------"); for (String key : streamManager.getStreamKeys()) { PcapLiveRunner runner = streamManager.get(key); PcapDevice device = runner.getDevice(); PcapStat stat = streamManager.getStat(key); PcapDeviceMetadata metadata = device.getMetadata(); context.printf("%s: %s %s\n", key, metadata.getDescription(), stat.toString()); } } public void devices(String[] args) { context.println("Available Devices"); context.println("-----------------------"); int i = 1; for (PcapDeviceMetadata metadata : PcapDeviceManager.getDeviceMetadataList()) { context.printf("[%2d] %s %s\n", i++, metadata.getName(), metadata.getDescription()); } } @ScriptUsage(description = "print pcap device stats", arguments = { @ScriptArgument(name = "alias", type = "string", description = "the alias of the pcap device") }) public void stats(String[] args) { String alias = args[0]; PcapStat stat = streamManager.getStat(alias); if (stat == null) { context.println("device not found"); return; } context.println(stat.toString()); } @ScriptUsage(description = "print pcap device tcp sessions", arguments = { @ScriptArgument(name = "alias", type = "string", description = "the alias of the pcap device"), @ScriptArgument(name = "ip filter", type = "string", description = "ip filter", optional = true) }) public void sessions(String[] args) { PcapLiveRunner runner = streamManager.get(args[0]); if (runner == null) { context.println("device not found"); return; } List<TcpSession> sessions = new ArrayList<TcpSession>(runner.getTcpDecoder().getCurrentSessions()); Collections.sort(sessions, new Comparator<TcpSession>() { @Override public int compare(TcpSession o1, TcpSession o2) { return (o1.getId() - o2.getId()); } }); String filter = null; if (args.length > 1) filter = args[1]; for (TcpSession session : sessions) { if (filter == null || session.getKey().getServerIp().getHostAddress().equals(filter) || session.getKey().getClientIp().getHostAddress().equals(filter)) context.println("[" + session.getId() + "] " + session.toString()); } } @ScriptUsage(description = "send tcp reset packet", arguments = { @ScriptArgument(name = "alias", type = "string", description = "alias of the pcap device"), @ScriptArgument(name = "session id", type = "integer", description = "session id") }) public void tcpReset(String[] args) { PcapLiveRunner runner = streamManager.get(args[0]); if (runner == null) { context.println("device not found"); return; } PcapDevice device = runner.getDevice(); Set<Integer> ids = new HashSet<Integer>(); for (int i = 1; i < args.length; i++) { try { ids.add(Integer.parseInt(args[i])); } catch (NumberFormatException e) { } } for (TcpSession session : runner.getTcpDecoder().getCurrentSessions()) { try { if (ids.contains(session.getId())) sendTcpReset(device, session); } catch (IOException e) { logger.error("kraken pcap: io error", e); } } } private void sendTcpReset(PcapDevice device, TcpSession session) throws IOException { InetAddress sIp = session.getKey().getServerIp(); int sPort = session.getKey().getServerPort(); InetAddress cIp = session.getKey().getClientIp(); int cPort = session.getKey().getClientPort(); device.setFilter(String.format("tcp and src net %s and src port %d and dst net %s and dst port %d", cIp.getHostAddress(), cPort, sIp.getHostAddress(), sPort)); Buffer packet = device.getPacket().getPacketData(); byte[] dstMac = new byte[6]; byte[] srcMac = new byte[6]; // ethernet frame (14 bytes) packet.gets(dstMac); packet.gets(srcMac); packet.getShort(); // ignore type (ethernet frame) int seq = TcpPacket.parse(Ipv4Packet.parse(packet)).getSeq(); TcpPacket tcp = new TcpPacket.Builder().src(cIp, cPort).dst(sIp, sPort).window(0).seq(seq).rst().build(); Ipv4Packet ip = new Ipv4Packet.Builder().src(cIp).dst(sIp).proto(InternetProtocol.TCP).data(tcp.getBuffer()) .build(); Injectable ethernet = new EthernetFrame.Builder().src(new MacAddress(srcMac)).dst(new MacAddress(dstMac)) .type(EthernetType.IPV4).data(ip.getBuffer()).build(); device.write(ethernet.getBuffer()); } @ScriptUsage(description = "open and register pcap device", arguments = { @ScriptArgument(name = "alias", type = "string", description = "alias of the pcap device"), @ScriptArgument(name = "device index", type = "int", description = "index of the pcap device"), @ScriptArgument(name = "timeout", type = "int", description = "milliseconds"), @ScriptArgument(name = "promiscuous mode", type = "string", description = "promisc or nonpromisc", optional = true), @ScriptArgument(name = "bpf", type = "string", description = "bpf filter expression", optional = true) }) public void open(String[] args) { try { String alias = args[0]; int select = Integer.parseInt(args[1]); int milliseconds = Integer.parseInt(args[2]); Promiscuous promisc = null; String filter = null; if (args.length > 4) filter = args[4]; if (args.length > 3) promisc = args[3].equals("promisc") ? Promiscuous.On : Promiscuous.Off; String deviceName = null; int i = 1; for (PcapDeviceMetadata metadata : PcapDeviceManager.getDeviceMetadataList()) { if (i == select) { deviceName = metadata.getName(); break; } i++; } streamManager.start(alias, deviceName, milliseconds, promisc, filter); context.println("stream opened"); } catch (IOException e) { context.println("open failed"); } } @ScriptUsage(description = "close and unregister the pcap device", arguments = { @ScriptArgument(name = "alias", type = "string", description = "alias of the pcap device") }) public void close(String[] args) { String alias = args[0]; if (streamManager.get(alias) == null) { context.println("stream not found"); return; } streamManager.stop(alias); context.println("stopped"); } }