1 module libtun.adapter; 2 3 extern (C) int ioctl(int fd, ulong request, void* data); 4 extern (C) int open(char* path, int flags); 5 6 import core.stdc.stdio; 7 8 9 /** 10 * TUN maintenance routines in `tunctl.c` 11 */ 12 extern (C) int createTun(char* interfaceName, int iffFlags); 13 extern (C) int destroyTun(int fd); 14 extern (C) int tunWrite(int fd, char* data, int length); 15 extern (C) int tunRead(int fd, char* data, int amount); 16 17 public class TUNAdapter 18 { 19 /* Tunnel device descriptor */ 20 private int tunFD; 21 private bool isClosed; 22 23 /* Temporary scratchpad buffer */ 24 private byte[] scratch; 25 26 27 this(string interfaceName, AdapterType adapterType = AdapterType.TAP) 28 { 29 init(interfaceName, adapterType); 30 } 31 32 private void init(string interfaceName, AdapterType adapterType) 33 { 34 tunFD = createTun(cast(char*)interfaceName, 4096|adapterType); 35 if(tunFD < 0) 36 { 37 throw new TUNException("Error creating tun device"); 38 } 39 40 /* TODO: Get device MTU and add functions for setting it */ 41 ushort mtu = cast(ushort)-1; 42 scratch.length = mtu; 43 } 44 45 private void sanityCheck() 46 { 47 if(isClosed) 48 { 49 throw new TUNException("Cannot operate on closed tunnel device"); 50 } 51 } 52 53 public void close() 54 { 55 sanityCheck(); 56 57 isClosed = true; 58 destroyTun(tunFD); 59 } 60 61 62 public void receive(ref byte[] buffer) 63 { 64 sanityCheck(); 65 66 67 68 /** 69 * We read with a request of maximum possible 70 * Ethernet frame size (-1 -> 2 bytes) 65535, 71 * this ensures our buffer fills up in all cases 72 * but we get returned either < 0 or > 0. 73 * 74 * Former, systemcall read error 75 * Latter, ethernet frame size 76 */ 77 int status = tunRead(tunFD, cast(char*)scratch.ptr, cast(int)scratch.length); 78 79 80 if(status < 0) 81 { 82 throw new TUNException("Read failed"); 83 } 84 else if(status == 0) 85 { 86 assert(false); 87 } 88 else 89 { 90 /* Copy the data into their buffer (and of correct length) */ 91 buffer = scratch[0..status].dup; 92 } 93 94 95 96 97 98 99 100 101 102 } 103 104 public void send(byte[] buffer) 105 { 106 sanityCheck(); 107 108 tunWrite(tunFD, cast(char*)buffer.ptr, cast(int)buffer.length); 109 } 110 111 112 public void setDeviceMTU(ushort mtu) 113 { 114 /* TODO: Set the MTU on the device */ 115 116 /* TODO: Set the scratchpad to match the MTU */ 117 scratch.length = mtu; 118 } 119 120 121 } 122 123 public final class TUNException : Exception 124 { 125 this(string msg) 126 { 127 super(msg); 128 } 129 } 130 131 public enum AdapterType : byte 132 { 133 TUN = 1, 134 TAP = 2 135 }