IPv6 traffic logging

This commit is contained in:
M66B 2016-01-08 14:58:21 +01:00
parent ae4949852a
commit 9db05d1dd0
4 changed files with 160 additions and 109 deletions

View File

@ -81,23 +81,19 @@ public class LogAdapter extends CursorAdapter {
// Set values
tvTime.setText(new SimpleDateFormat("dd HH:mm:ss").format(time));
tvIP.setText(whois);
if (version == 4)
if (protocol == IPv4Packet.IPv4Header.ICMP)
tvProtocol.setText("I");
else if (protocol == IPv4Packet.IPv4Header.TCP)
tvProtocol.setText("T");
else if (protocol == IPv4Packet.IPv4Header.UDP)
tvProtocol.setText("U");
else
tvProtocol.setText(protocol < 0 ? "" : Integer.toString(protocol));
if (protocol == Packet.Protocol.ICMP)
tvProtocol.setText("I");
else if (protocol == Packet.Protocol.TCP)
tvProtocol.setText("T");
else if (protocol == Packet.Protocol.UDP)
tvProtocol.setText("U");
else
tvProtocol.setText("");
tvProtocol.setText(protocol < 0 ? "" : Integer.toString(protocol));
tvPort.setText(port < 0 ? "" : Integer.toString(port));
tvFlags.setText(flags);
tvUid.setText(uid < 0 ? "" : Integer.toString(uid % 100000));
tvUid.setText(uid < 0 ? "" : uid == 0 ? "root" : Integer.toString(uid % 100000));
}
}

View File

@ -25,32 +25,62 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.Scanner;
public class IPv4Packet {
public class Packet {
private static final String TAG = "NetGuard.Packet";
private ByteBuffer packet;
public int version;
public IPv4Header IPv4;
public UDPHeader UDP = null;
public IPv6Header IPv6;
public Packet.UDP UDP = null;
public TCP TCP = null;
private IPv4Packet() {
public static class Protocol {
// https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers
public static final int HOPOPT = 0; // IPv6 Hop-by-Hop Option
public static final int ICMP = 1; // Internet Control Message Protocol
public static final int IGMP = 2; // Internet Group Management Protocol
public static final int TCP = 6; // Transmission Control Protocol
public static final int UDP = 17; // User Packet Protocol
public static final int ENCAP = 41; // IPv6 encapsulation
public static final int OSPF = 89; // Open Shortest Path First
public static final int SCTP = 132; // Stream Control Transmission Protocol
}
public IPv4Packet(ByteBuffer buffer) throws IOException {
private Packet() {
}
public Packet(ByteBuffer buffer) throws IOException {
packet = buffer;
try {
IPv4 = new IPv4Header(buffer);
if (IPv4.protocol == IPv4.UDP)
UDP = new UDPHeader(buffer);
else if (IPv4.protocol == IPv4.TCP)
TCP = new TCP(IPv4.sourceAddress, IPv4.destinationAddress, buffer);
else
throw new IOException("Unsupported protocol=" + IPv4.protocol);
// Peek version
int pos = buffer.position();
this.version = (buffer.get() >> 4);
buffer.position(pos);
if (this.version == 4) {
IPv4 = new IPv4Header(buffer);
if (IPv4.protocol == Protocol.UDP)
UDP = new UDP(buffer);
else if (IPv4.protocol == Protocol.TCP)
TCP = new TCP(this.version, IPv4.sourceAddress, IPv4.destinationAddress, buffer);
} else if (this.version == 6) {
IPv6 = new IPv6Header(buffer);
if (IPv6.nextHeader == Protocol.UDP)
UDP = new UDP(buffer);
else if (IPv6.nextHeader == Protocol.TCP)
TCP = new TCP(this.version, IPv6.sourceAddress, IPv6.destinationAddress, buffer);
} else
throw new IOException("Unknown version=" + this.version);
} catch (IOException ex) {
throw new IOException(ex.toString() + " " + this);
}
@ -58,7 +88,11 @@ public class IPv4Packet {
public void validate() throws IOException {
try {
IPv4.validate();
if (version == 4)
IPv4.validate();
else if (version == 6)
IPv6.validate();
if (this.UDP != null)
this.UDP.validate();
if (this.TCP != null)
@ -91,6 +125,45 @@ public class IPv4Packet {
out.write(r);
}
public InetAddress getDestinationAddress() {
if (this.version == 4)
return this.IPv4.destinationAddress;
else
return this.IPv6.destinationAddress;
}
public int getProtocol() {
if (this.version == 4)
return this.IPv4.protocol;
else
return this.IPv6.nextHeader;
}
public int getDestinationPort() {
if (this.TCP != null)
return this.TCP.destinationPort;
else if (this.UDP != null)
return this.UDP.destinationPort;
return -1;
}
public String getFlags() {
String flags = "";
if (this.TCP != null) {
if (this.TCP.SYN)
flags += "S";
if (this.TCP.ACK)
flags += "A";
if (this.TCP.PSH)
flags += "P";
if (this.TCP.FIN)
flags += "F";
if (this.TCP.RST)
flags += "R";
}
return flags;
}
public String toShortString() {
StringBuilder sb = new StringBuilder();
sb.append(this.IPv4.sourceAddress);
@ -151,14 +224,6 @@ public class IPv4Packet {
public int calculatedHeaderChecksum;
public static final int ICMP = 1; // Internet Control Message Protocol
public static final int IGMP = 2; // Internet Group Management Protocol
public static final int TCP = 6; // Transmission Control Protocol
public static final int UDP = 17; // User Packet Protocol
public static final int ENCAP = 41; // IPv6 encapsulation
public static final int OSPF = 89; // Open Shortest Path First
public static final int SCTP = 132; // Stream Control Transmission Protocol
private IPv4Header(int protocol, InetAddress sourceAddress, InetAddress destinationAddress) {
this.version = 4;
this.IHL = 5;
@ -279,14 +344,40 @@ public class IPv4Packet {
}
}
// https://en.wikipedia.org/wiki/IPv6_packet
public static class IPv6Header {
public int nextHeader;
public InetAddress sourceAddress;
public InetAddress destinationAddress;
public IPv6Header(ByteBuffer buffer) throws IOException {
int pos = buffer.position();
buffer.position(pos + 6);
nextHeader = buffer.get() & 0xFF;
buffer.position(pos + 8);
byte[] sourceBytes = new byte[16];
buffer.get(sourceBytes, 0, 16);
sourceAddress = Inet6Address.getByAddress(sourceBytes);
buffer.position(pos + 24);
byte[] destinationBytes = new byte[16];
buffer.get(destinationBytes, 0, 16);
destinationAddress = Inet6Address.getByAddress(destinationBytes);
}
public void validate() throws IOException {
}
}
// https://en.wikipedia.org/wiki/User_Datagram_Protocol
public class UDPHeader {
public static class UDP {
public int sourcePort;
public int destinationPort;
public int length;
public int checksum;
public UDPHeader(ByteBuffer buffer) {
public UDP(ByteBuffer buffer) {
int pos = buffer.position();
this.sourcePort = buffer.getShort() & 0xFFFF;
@ -334,7 +425,7 @@ public class IPv4Packet {
this.options = new byte[0];
}
public TCP(InetAddress source, InetAddress destination, ByteBuffer buffer) {
public TCP(int version, InetAddress source, InetAddress destination, ByteBuffer buffer) {
int pos = buffer.position();
this.sourcePort = buffer.getShort() & 0xFFFF;
@ -370,17 +461,19 @@ public class IPv4Packet {
buffer.putShort(pos + 16, (short) 0);
// pseudo header
ByteBuffer cc = ByteBuffer.allocate(12 + buffer.position() - pos);
cc.put(source.getAddress());
cc.put(destination.getAddress());
cc.put((byte) 0);
cc.put((byte) 6);
cc.putShort((short) (buffer.position() - pos));
// TODO: combine two checksums
for (int i = pos; i < buffer.position(); i++)
cc.put(buffer.get(i));
if (version == 4) {
ByteBuffer cc = ByteBuffer.allocate(12 + buffer.position() - pos);
cc.put(source.getAddress());
cc.put(destination.getAddress());
cc.put((byte) 0);
cc.put((byte) 6);
cc.putShort((short) (buffer.position() - pos));
// TODO: combine two checksums
for (int i = pos; i < buffer.position(); i++)
cc.put(buffer.get(i));
this.calculatedChecksum = Util.getChecksum(cc, 0, cc.limit());
this.calculatedChecksum = Util.getChecksum(cc, 0, cc.limit());
}
}
private int getFlagValue() {
@ -516,19 +609,21 @@ public class IPv4Packet {
return -1;
StringBuilder addr = new StringBuilder();
byte[] b = this.IPv4.sourceAddress.getAddress();
byte[] b = (this.version == 4 ? this.IPv4.sourceAddress.getAddress() : this.IPv6.sourceAddress.getAddress());
for (int i = b.length - 1; i >= 0; i--)
addr.append(String.format("%02X", b[i]));
String port = String.format("%04X", this.TCP == null ? this.UDP.sourcePort : this.TCP.sourcePort);
int uid = scanUid("0000000000000000FFFF0000" + addr.toString() + ":" + port, this.TCP == null ? "/proc/net/udp6" : "/proc/net/tcp6");
if (uid < 0)
uid = scanUid(addr.toString() + ":" + port, this.TCP == null ? "/proc/net/udp" : "/proc/net/tcp");
if (uid < 0 && this.UDP != null)
uid = scanUid("00000000:" + port, "/proc/net/udp");
// IPv6 5014002A010C13400000000084000000 = 2a00:1450:4013:c01::84
int uid = 0;
if (this.version == 4) {
uid = scanUid("0000000000000000FFFF0000" + addr.toString() + ":" + port, this.TCP == null ? "/proc/net/udp6" : "/proc/net/tcp6");
if (uid < 0)
uid = scanUid(addr.toString() + ":" + port, this.TCP == null ? "/proc/net/udp" : "/proc/net/tcp");
if (uid < 0 && this.UDP != null)
uid = scanUid("00000000:" + port, "/proc/net/udp");
} else
uid = scanUid(addr.toString() + ":" + port, this.TCP == null ? "/proc/net/udp6" : "/proc/net/tcp6");
return uid;
}

View File

@ -63,8 +63,6 @@ import android.widget.RemoteViews;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
@ -699,10 +697,22 @@ public class SinkholeService extends VpnService {
int length = in.read(buffer.array());
if (length > 0) {
buffer.limit(length);
processPacket(buffer);
Packet pkt = new Packet(buffer);
Log.i(TAG, "Packet to " + pkt.getDestinationAddress().toString() +
"/" + pkt.getDestinationPort() +
" " + pkt.getFlags() +
" " + pkt.getProtocol());
new DatabaseHelper(SinkholeService.this).insertLog(
pkt.version,
pkt.getDestinationAddress().toString(),
pkt.getProtocol(),
pkt.getDestinationPort(),
pkt.getFlags(),
pkt.getUid()).close();
}
} catch (Throwable ex) {
Log.e(TAG, ex.toString());
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
}
Log.i(TAG, "End receiving");
} catch (Throwable ex) {
@ -729,57 +739,6 @@ public class SinkholeService extends VpnService {
receiveThread.start();
}
private void processPacket(ByteBuffer buffer) throws IOException {
byte version = (byte) (buffer.get() >> 4);
if (version == 4) {
buffer.position(0);
IPv4Packet pkt = new IPv4Packet(buffer);
int port = -1;
if (pkt.TCP != null)
port = pkt.TCP.destinationPort;
else if (pkt.UDP != null)
port = pkt.UDP.destinationPort;
String flags = "";
if (pkt.TCP != null) {
if (pkt.TCP.SYN)
flags += "S";
if (pkt.TCP.ACK)
flags += "A";
if (pkt.TCP.PSH)
flags += "P";
if (pkt.TCP.FIN)
flags += "F";
if (pkt.TCP.RST)
flags += "R";
}
Log.i(TAG, "Packet to " + pkt.IPv4.destinationAddress.toString() + ":" + port + " " + flags);
new DatabaseHelper(SinkholeService.this).insertLog(
version,
pkt.IPv4.destinationAddress.toString(),
pkt.IPv4.protocol,
port,
flags,
pkt.getUid()).close();
} else if (version == 6) {
buffer.position(24);
byte[] addressBytes = new byte[16];
buffer.get(addressBytes, 0, 16);
InetAddress ina = Inet6Address.getByAddress(addressBytes);
Log.i(TAG, "Packet to " + ina);
new DatabaseHelper(SinkholeService.this).insertLog(
version,
ina.toString(),
-1,
-1,
"",
-1).close();
}
}
private void stopReceiving() {
if (receiveThread != null)
receiveThread.interrupt();

View File

@ -22,9 +22,10 @@
<TextView
android:id="@+id/tvProtocol"
android:layout_width="8dp"
android:layout_width="16dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="end"
android:textAppearance="@android:style/TextAppearance.Material.Small" />
<TextView