// Path: mitm/src/main/java/uk/ac/cam/gpe21/droidssl/mitm/util/CLibrary.java
// public interface CLibrary extends Library {
// 	public final CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);
// 
// 	/* from /usr/include/bits/socket.h */
// 	public final int PF_INET = 2;
// 	public final int PF_INET6 = 10;
// 
// 	/* from /usr/include/bits/in.h */
// 	public final int SOL_IP = 0;
// 	public final int SOL_IPV6 = 41;
// 	public final int IP_TRANSPARENT = 19;
// 
// 	/* from /usr/include/linux/netfilter_ipv4.h */
// 	public final int SO_ORIGINAL_DST = 80;
// 
// 	/* from /usr/include/linux/netfilter_ipv6/ip6_tables.h */
// 	public final int IP6T_SO_ORIGINAL_DST = 80;
// 
// 	/* from /usr/include/linux/in.h */
// 	public final class sockaddr_in extends Structure {
// 		public short sin_family;
// 		public byte[] sin_port = new byte[2];
// 		public byte[] sin_addr = new byte[4];
// 		public byte[] sin_zero = new byte[8];
// 
// 		@Override
// 		protected List getFieldOrder() {
// 			return Arrays.asList("sin_family", "sin_port", "sin_addr", "sin_zero");
// 		}
// 	}
// 
// 	/* from /usr/include/linux/in6.h */
// 	public final class sockaddr_in6 extends Structure {
// 		public short  sin6_family;
// 		public byte[] sin6_port     = new byte[2];
// 		public byte[] sin6_flowinfo = new byte[4];
// 		public byte[] sin6_addr     = new byte[16];
// 		public int    sin6_scope_id;
// 
// 		@Override
// 		protected List getFieldOrder() {
// 			return Arrays.asList("sin6_family", "sin6_port", "sin6_flowinfo", "sin6_addr", "sin6_scope_id");
// 		}
// 	}
// 
// 	/* from /usr/include/sys/socket.h */
// 	public int getsockopt(int socket, int level, int option_name, Pointer option_value, IntByReference option_len) throws LastErrorException;
// 	public int setsockopt(int socket, int level, int option_name, Pointer option_value, int option_len) throws LastErrorException;
// 
// 	/* from /usr/include/string.h */
// 	public String strerror(int errnum);
// }


import com.sun.jna.LastErrorException;
import com.sun.jna.ptr.IntByReference;
import uk.ac.cam.gpe21.droidssl.mitm.util.CLibrary;
import javax.net.ssl.SSLSocket;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.*;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

			if (!(in instanceof FileInputStream))
				throw new IOException("sockInput is not an instance of FileInputStream");

			FileInputStream fin = (FileInputStream) in;
			FileDescriptor fd = fin.getFD();

			return FD.getInt(fd);
		} catch (IllegalAccessException ex) {
			throw new IOException(ex);
		}
	}

	public static InetSocketAddress getOriginalDestination(Socket socket) throws IOException {
		InetAddress localAddress = socket.getLocalAddress();
		if (localAddress instanceof Inet4Address) {
			return getOriginalDestination4(socket);
		} else if (localAddress instanceof Inet6Address) {
			return getOriginalDestination6(socket);
		} else {
			throw new IOException("Unknown local address type (expected java.net.Inet{4,6}Address): " + localAddress.getClass().getName());
		}
	}

	public static InetSocketAddress getOriginalDestination4(Socket socket) throws IOException {
		int fd = getFileDescriptor(socket);

		CLibrary.sockaddr_in addr = new CLibrary.sockaddr_in();
		try {
			IntByReference len = new IntByReference(addr.size());
// Path: mitm/src/main/java/uk/ac/cam/gpe21/droidssl/mitm/util/CLibrary.java
// public interface CLibrary extends Library {
// 	public final CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);
// 
// 	/* from /usr/include/bits/socket.h */
// 	public final int PF_INET = 2;
// 	public final int PF_INET6 = 10;
// 
// 	/* from /usr/include/bits/in.h */
// 	public final int SOL_IP = 0;
// 	public final int SOL_IPV6 = 41;
// 	public final int IP_TRANSPARENT = 19;
// 
// 	/* from /usr/include/linux/netfilter_ipv4.h */
// 	public final int SO_ORIGINAL_DST = 80;
// 
// 	/* from /usr/include/linux/netfilter_ipv6/ip6_tables.h */
// 	public final int IP6T_SO_ORIGINAL_DST = 80;
// 
// 	/* from /usr/include/linux/in.h */
// 	public final class sockaddr_in extends Structure {
// 		public short sin_family;
// 		public byte[] sin_port = new byte[2];
// 		public byte[] sin_addr = new byte[4];
// 		public byte[] sin_zero = new byte[8];
// 
// 		@Override
// 		protected List getFieldOrder() {
// 			return Arrays.asList("sin_family", "sin_port", "sin_addr", "sin_zero");
// 		}
// 	}
// 
// 	/* from /usr/include/linux/in6.h */
// 	public final class sockaddr_in6 extends Structure {
// 		public short  sin6_family;
// 		public byte[] sin6_port     = new byte[2];
// 		public byte[] sin6_flowinfo = new byte[4];
// 		public byte[] sin6_addr     = new byte[16];
// 		public int    sin6_scope_id;
// 
// 		@Override
// 		protected List getFieldOrder() {
// 			return Arrays.asList("sin6_family", "sin6_port", "sin6_flowinfo", "sin6_addr", "sin6_scope_id");
// 		}
// 	}
// 
// 	/* from /usr/include/sys/socket.h */
// 	public int getsockopt(int socket, int level, int option_name, Pointer option_value, IntByReference option_len) throws LastErrorException;
// 	public int setsockopt(int socket, int level, int option_name, Pointer option_value, int option_len) throws LastErrorException;
// 
// 	/* from /usr/include/string.h */
// 	public String strerror(int errnum);
// }


// Path: mitm/src/main/java/uk/ac/cam/gpe21/droidssl/mitm/socket/SocketUtils.java
import com.sun.jna.LastErrorException;
import com.sun.jna.ptr.IntByReference;
import uk.ac.cam.gpe21.droidssl.mitm.util.CLibrary;
import javax.net.ssl.SSLSocket;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.*;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;


			if (!(in instanceof FileInputStream))
				throw new IOException("sockInput is not an instance of FileInputStream");

			FileInputStream fin = (FileInputStream) in;
			FileDescriptor fd = fin.getFD();

			return FD.getInt(fd);
		} catch (IllegalAccessException ex) {
			throw new IOException(ex);
		}
	}

	public static InetSocketAddress getOriginalDestination(Socket socket) throws IOException {
		InetAddress localAddress = socket.getLocalAddress();
		if (localAddress instanceof Inet4Address) {
			return getOriginalDestination4(socket);
		} else if (localAddress instanceof Inet6Address) {
			return getOriginalDestination6(socket);
		} else {
			throw new IOException("Unknown local address type (expected java.net.Inet{4,6}Address): " + localAddress.getClass().getName());
		}
	}

	public static InetSocketAddress getOriginalDestination4(Socket socket) throws IOException {
		int fd = getFileDescriptor(socket);

		CLibrary.sockaddr_in addr = new CLibrary.sockaddr_in();
		try {
			IntByReference len = new IntByReference(addr.size());
			CLibrary.INSTANCE.getsockopt(fd, CLibrary.SOL_IP, CLibrary.SO_ORIGINAL_DST, addr.getPointer(), len);