2024-06-07 18:29:53 -04:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2024-06-09 14:08:30 -04:00
|
|
|
// "bufio"
|
2024-06-07 18:29:53 -04:00
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"os"
|
2024-06-09 14:08:30 -04:00
|
|
|
"net"
|
2024-06-07 18:29:53 -04:00
|
|
|
"strconv"
|
2024-06-09 14:08:30 -04:00
|
|
|
"io"
|
|
|
|
"context"
|
|
|
|
"time"
|
2024-06-07 18:29:53 -04:00
|
|
|
"math/rand"
|
2024-06-09 14:08:30 -04:00
|
|
|
"bytes"
|
|
|
|
|
|
|
|
"golang.org/x/crypto/ssh"
|
2024-06-07 18:29:53 -04:00
|
|
|
|
2024-06-09 14:08:30 -04:00
|
|
|
// "github.com/songgao/packets/ethernet"
|
2024-06-07 18:29:53 -04:00
|
|
|
"github.com/songgao/water"
|
|
|
|
|
|
|
|
"github.com/vishvananda/netlink"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Client struct {
|
|
|
|
ifce *water.Interface
|
|
|
|
hostname string
|
|
|
|
addr *netlink.Addr
|
2024-06-09 14:08:30 -04:00
|
|
|
addr_str string
|
2024-06-07 18:29:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// -- funcs --
|
|
|
|
|
|
|
|
// writes out desired hostname to file. generates a small bash script for
|
|
|
|
// the client to run
|
|
|
|
//func generateNewClient() {
|
|
|
|
//
|
|
|
|
// var desired_hostname string
|
|
|
|
// fmt.Printf("Please enter a desired hostname for the new client: ")
|
|
|
|
//
|
|
|
|
// scanner := bufio.NewScanner(os.Stdin)
|
|
|
|
// scanner.Scan()
|
|
|
|
// err := scanner.Err()
|
|
|
|
// if err != nil {
|
|
|
|
// log.Fatal(err)
|
|
|
|
// panic(err)
|
|
|
|
// }
|
|
|
|
// desired_hostname = scanner.Text()
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//}
|
|
|
|
|
|
|
|
// maps ip --> hostname
|
|
|
|
// used to verify collisions
|
|
|
|
var client_leases = make(map[string]string)
|
|
|
|
|
2024-06-09 14:08:30 -04:00
|
|
|
var mode string
|
|
|
|
func detectMode() {
|
|
|
|
mode = os.Getenv("LAZYVPN_MODE")
|
|
|
|
if len(mode) == 0 {
|
|
|
|
fmt.Println("Mode not set! assuming CLIENT")
|
|
|
|
mode = "CLIENT"
|
|
|
|
}
|
|
|
|
fmt.Printf("Running in mode %s\n", mode)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-06-07 18:29:53 -04:00
|
|
|
func generateClientTUN(hn string) Client {
|
|
|
|
|
|
|
|
// configure TUN interface
|
|
|
|
config := water.Config{
|
|
|
|
DeviceType: water.TUN,
|
|
|
|
}
|
|
|
|
config.Name = "tun_"+hn
|
|
|
|
|
|
|
|
|
|
|
|
cl_ifce, err := water.New(config)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate a free address to assign
|
|
|
|
var cl_Addr_str string
|
2024-06-09 14:08:30 -04:00
|
|
|
if mode == "CLIENT" {
|
|
|
|
// This is a bad way of doing it, and only accounts for local conflicts
|
|
|
|
// theres definitely a way to find if it conflicts somewhere else
|
|
|
|
// ideally, it shouldnt be locked to this 16 block, either. eventually,
|
|
|
|
// the allowed range (CIDR included) should be defined.
|
|
|
|
// this is an alpha for now, just to get *something* nice working
|
|
|
|
r := rand.New(rand.NewSource(255))
|
|
|
|
for {
|
|
|
|
var b1 int = int(r.Int31n(255))
|
|
|
|
var b2 int = int(r.Int31n(255))
|
|
|
|
cl_Addr_str = "." + strconv.Itoa(b1) + "." + strconv.Itoa(b2)
|
|
|
|
|
|
|
|
fmt.Println(cl_Addr_str)
|
|
|
|
|
|
|
|
_, isLeased := client_leases[cl_Addr_str]
|
|
|
|
if !isLeased {
|
|
|
|
break
|
|
|
|
}
|
2024-06-07 18:29:53 -04:00
|
|
|
}
|
2024-06-09 14:08:30 -04:00
|
|
|
} else {
|
|
|
|
// its the server
|
|
|
|
cl_Addr_str = ".0.1"
|
2024-06-07 18:29:53 -04:00
|
|
|
}
|
2024-06-09 14:08:30 -04:00
|
|
|
|
2024-06-07 18:29:53 -04:00
|
|
|
cl_Link, err := netlink.LinkByName(config.Name)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2024-06-09 14:08:30 -04:00
|
|
|
cl_Addr_str = "169.254"+cl_Addr_str
|
|
|
|
cl_Addr, err := netlink.ParseAddr(cl_Addr_str+"/16")
|
2024-06-07 18:29:53 -04:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// register addr -> ifce with host
|
|
|
|
netlink.AddrAdd(cl_Link, cl_Addr)
|
|
|
|
|
|
|
|
return Client {
|
|
|
|
ifce: cl_ifce,
|
|
|
|
hostname: hn,
|
|
|
|
addr: cl_Addr,
|
2024-06-09 14:08:30 -04:00
|
|
|
addr_str: cl_Addr_str,
|
2024-06-07 18:29:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-09 14:08:30 -04:00
|
|
|
func StartListener(addr string) {
|
|
|
|
// listen on port 28173
|
|
|
|
l, err := net.Listen("tcp", addr+":28173")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
2024-06-07 18:29:53 -04:00
|
|
|
}
|
2024-06-09 14:08:30 -04:00
|
|
|
defer l.Close()
|
|
|
|
|
|
|
|
fmt.Printf("Listening on %s port 28173", addr)
|
2024-06-07 18:29:53 -04:00
|
|
|
|
|
|
|
for {
|
2024-06-09 14:08:30 -04:00
|
|
|
// Wait for a connection.
|
|
|
|
conn, err := l.Accept()
|
2024-06-07 18:29:53 -04:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2024-06-09 14:08:30 -04:00
|
|
|
|
|
|
|
// Handle the connection in a new goroutine.
|
|
|
|
// The loop then returns to accepting, so that
|
|
|
|
// multiple connections may be served concurrently.
|
|
|
|
go func(c net.Conn) {
|
|
|
|
// Echo all incoming data.
|
|
|
|
io.Copy(c, c)
|
|
|
|
// Shut down the connection.
|
|
|
|
c.Close()
|
|
|
|
}(conn)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func StartDialer() {
|
|
|
|
var d net.Dialer
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
fmt.Printf("Attempting autodiscovery")
|
|
|
|
conn, err := d.DialContext(ctx, "tcp", "169.254.0.1:28173")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Failed to dial: %v", err)
|
2024-06-07 18:29:53 -04:00
|
|
|
}
|
2024-06-09 14:08:30 -04:00
|
|
|
defer conn.Close()
|
2024-06-07 18:29:53 -04:00
|
|
|
|
2024-06-09 14:08:30 -04:00
|
|
|
if _, err := conn.Write([]byte("Hello, World!")); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
// Detect if we are in CLIENT or SERVER mode
|
|
|
|
detectMode()
|
|
|
|
|
|
|
|
// Zeroth stage - gather info
|
|
|
|
var hostKey ssh.PublicKey
|
|
|
|
|
|
|
|
|
|
|
|
config := &ssh.ClientConfig {
|
|
|
|
User: os.Getenv("LAZYUSER"),
|
|
|
|
Auth: []ssh.authmethod {
|
|
|
|
ssh.Password(os.Getenv("LAZYPASS")),
|
|
|
|
},
|
|
|
|
HostKeyCallback: ssh.FixedHostKey(hostKey),
|
|
|
|
}
|
|
|
|
|
|
|
|
// First stage - attempt to connect to public host
|
|
|
|
var host string = "192.168.122.1"
|
|
|
|
fmt.Printf("Dialing host %s....\n", host)
|
|
|
|
client, err := ssh.Dial("tcp", host+":22278", config)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Failed to dial: ", err)
|
|
|
|
}
|
|
|
|
defer client.Close()
|
|
|
|
|
|
|
|
// Final stage
|
|
|
|
if mode == "SERVER" {
|
|
|
|
// open, listen and wait
|
|
|
|
StartListener(registered_client.addr_str)
|
|
|
|
} else {
|
|
|
|
// connect to far end
|
|
|
|
StartDialer()
|
|
|
|
}
|
2024-06-07 18:29:53 -04:00
|
|
|
}
|