├── client.go ├── README.md ├── Makefile ├── error.go ├── .gitignore ├── interface_types.go ├── main.go ├── LICENSE ├── server.go └── interface.go /client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/codegangsta/cli" 4 | 5 | // RunClient runs client-side daemon 6 | func RunClient(c *cli.Context) { 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # icmp-tunnel 2 | Transparently tunnel your IP traffic through ICMP echo and reply packets 3 | 4 | ## TODO 5 | 6 | * Tap 7 | * `ip` command util 8 | * traffic forwarding 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | default: all 2 | 3 | all: 4 | @go build -race ||: 5 | 6 | server: all 7 | @sudo ./icmp-tunnel server ||: 8 | 9 | client: all 10 | @sudo ./icmp-tunnel client ||: 11 | 12 | -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // IError interface 4 | type IError interface { 5 | Error() string 6 | } 7 | 8 | // Error represents the error 9 | type Error struct { 10 | errString string 11 | } 12 | 13 | // Error returns the error message of the object 14 | func (e *Error) Error() string { 15 | return e.errString 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | icmp-tunnel 27 | -------------------------------------------------------------------------------- /interface_types.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // interfaces is the type of interface 4 | type interfaces string 5 | 6 | // Interface types 7 | var ( 8 | InterfaceTypeTap interfaces = "tap" 9 | InterfaceTypeTun interfaces = "tun" 10 | InterfaceTypeEth interfaces = "eth" 11 | InterfaceTypeVLan interfaces = "vlan" 12 | InterfaceTypeBr interfaces = "br" 13 | InterfaceTypeWLan interfaces = "wlan" 14 | InterfaceTypeAth interfaces = "ath" 15 | ) 16 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/codegangsta/cli" 7 | ) 8 | 9 | func main() { 10 | Run(os.Args) 11 | } 12 | 13 | // Run command line tool 14 | func Run(args []string) { 15 | 16 | app := cli.NewApp() 17 | 18 | app.Name = "icmp-tunnel" 19 | app.Usage = "Transparently tunnel your IP traffic through ICMP echo and reply packets" 20 | 21 | verboseFlag := cli.BoolFlag{ 22 | Name: "verbose, v", 23 | Usage: "Enable verbose logging", 24 | } 25 | 26 | app.Commands = []cli.Command{ 27 | { 28 | Name: "server", 29 | Usage: "Runs server", 30 | Action: RunServer, 31 | Flags: []cli.Flag{verboseFlag}, 32 | }, 33 | { 34 | Name: "client", 35 | Usage: "Runs client", 36 | Action: RunClient, 37 | Flags: []cli.Flag{verboseFlag}, 38 | }, 39 | } 40 | 41 | app.Run(args) 42 | 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Samuel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "golang.org/x/net/icmp" 7 | 8 | "github.com/codegangsta/cli" 9 | ) 10 | 11 | // RunServer runs server-side daemon 12 | func RunServer(c *cli.Context) { 13 | 14 | iface, err := CreateIface() 15 | if err != nil { 16 | panic(fmt.Sprintf("creating interface error: %v\n", err)) 17 | } 18 | defer iface.Close() 19 | 20 | conn, err := ListenICMP() 21 | if err != nil { 22 | panic(fmt.Sprintf("listen icmp packet error: %v\n", err)) 23 | } 24 | defer conn.Close() 25 | 26 | data := make(chan []byte) 27 | 28 | go func() { 29 | for { 30 | buffer := make([]byte, 1522) 31 | _, err := iface.Read(buffer) 32 | if err == nil { 33 | data <- buffer 34 | } 35 | } 36 | }() 37 | 38 | for { 39 | select { 40 | case buffer := <-data: 41 | fmt.Println(string(buffer[:])) 42 | } 43 | } 44 | } 45 | 46 | // CreateIface creates network interface 47 | func CreateIface() (*Interface, error) { 48 | 49 | // creates a tap interface 50 | iface, err := TapInterface() 51 | 52 | if err == nil { 53 | // set network interface ip 54 | iface.ParseIP(10, 0, 40, 1) 55 | iface.Up() 56 | } 57 | 58 | return iface, err 59 | } 60 | 61 | // ListenICMP listens to incoming ICMP packet 62 | func ListenICMP() (*icmp.PacketConn, error) { 63 | return icmp.ListenPacket("ip4:icmp", "0.0.0.0") 64 | } 65 | -------------------------------------------------------------------------------- /interface.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | "os/exec" 8 | "strings" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | // IfReq represents interface request 14 | type IfReq struct { 15 | Name [0x10]byte 16 | Flags uint16 17 | pad [0x28 - 0x10 - 2]byte 18 | } 19 | 20 | // Interface - the network interfaces 21 | type Interface struct { 22 | name string 23 | class interfaces 24 | device *os.File 25 | ipnet net.IPNet 26 | } 27 | 28 | // Name returns Interface name 29 | func (i *Interface) Name() string { 30 | return i.name 31 | } 32 | 33 | // Class returns Interface type 34 | func (i *Interface) Class() interfaces { 35 | return i.class 36 | } 37 | 38 | // Write implements io.Writer interface. 39 | func (i *Interface) Write(p []byte) (int, error) { 40 | return i.device.Write(p) 41 | } 42 | 43 | // Read implements io.Reader interface. 44 | func (i *Interface) Read(p []byte) (int, error) { 45 | return i.device.Read(p) 46 | } 47 | 48 | // Close to close interface 49 | func (i *Interface) Close() error { 50 | return i.device.Close() 51 | } 52 | 53 | // ParseIP parses ip address 54 | func (i *Interface) ParseIP(a, b, c, d byte) { 55 | self := net.IPv4(a, b, c, d) 56 | mask := self.DefaultMask() 57 | i.ipnet = net.IPNet{IP: self, Mask: mask} 58 | } 59 | 60 | // Up brings interface up/online 61 | func (i *Interface) Up() error { 62 | if err := exec.Command("ip", "link", "set", i.name, "up").Run(); err != nil { 63 | return err 64 | } 65 | if err := exec.Command("ip", "addr", "add", i.ipnet.String(), "dev", i.name).Run(); err != nil { 66 | return err 67 | } 68 | return nil 69 | } 70 | 71 | // NewInterface creates new interface 72 | func NewInterface(name string, class interfaces, device string, flags uint16) (*Interface, IError) { 73 | file, err := os.OpenFile(device, os.O_RDWR, 0) 74 | if err != nil { 75 | return nil, err 76 | } 77 | ifr := IfReq{} 78 | ifr.Flags = flags 79 | copy(ifr.Name[:], name) 80 | if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), uintptr(syscall.TUNSETIFF), uintptr(unsafe.Pointer(&ifr))); err != 0 { 81 | return nil, err 82 | } 83 | ifName := strings.Trim(string(ifr.Name[:]), "\x00") 84 | networkif := &Interface{class: class, name: ifName, device: file} 85 | return networkif, nil 86 | } 87 | 88 | // TapInterface creates tap interface 89 | func TapInterface(names ...string) (*Interface, IError) { 90 | var name string 91 | for _, val := range names { 92 | name = val 93 | break 94 | } 95 | return NewInterface(name, InterfaceTypeTap, "/dev/net/tun", 0x0002|0x1000) 96 | } 97 | 98 | // TunInterface creates tun interface 99 | func TunInterface(names ...string) (*Interface, IError) { 100 | var name string 101 | for _, val := range names { 102 | name = val 103 | break 104 | } 105 | return NewInterface(name, InterfaceTypeTun, "/dev/net/tun", 0x0001|0x1000) 106 | } 107 | 108 | // IPAddRoute to add route via ip command 109 | func IPAddRoute(dest, route, iface string) IError { 110 | scmd := fmt.Sprintf("ip -4 r a %s via %s dev %s", dest, route, iface) 111 | cmd := exec.Command("sh", "-c", scmd) 112 | if err := cmd.Run(); err != nil { 113 | return err 114 | } 115 | return nil 116 | } 117 | 118 | // IPDeleteRoute to remove route via ip command 119 | func IPDeleteRoute(dest string) IError { 120 | sargs := fmt.Sprintf("-4 route del %s", dest) 121 | args := strings.Split(sargs, " ") 122 | cmd := exec.Command("ip", args...) 123 | if err := cmd.Run(); err != nil { 124 | return err 125 | } 126 | return nil 127 | } 128 | --------------------------------------------------------------------------------