Initial commit

This commit is contained in:
Cadey Ratio 2017-01-18 01:57:18 -08:00
commit fc0962b16c
4 changed files with 339 additions and 0 deletions

29
cmd/api/main.go Normal file
View File

@ -0,0 +1,29 @@
package main
import (
"log"
"net/rpc"
"git.xeserv.us/xena/route/routerpc"
)
func main() {
client, err := rpc.DialHTTP("tcp", "127.0.0.1:9234")
if err != nil {
log.Fatal(err)
}
req := routerpc.AddHostRequest{
APIKey: "hunter2",
Hostname: "",
PrivKey: nil,
}
resp := &routerpc.AddHostResponse{}
err = client.Call("Urls.AddHost", req, resp)
if err != nil {
log.Fatal(err)
}
log.Printf("Created host %s with token %s", resp.Hostname, resp.Token)
}

30
cmd/httpagent/main.go Normal file
View File

@ -0,0 +1,30 @@
package main
import (
"flag"
"log"
"github.com/koding/tunnel"
)
var (
token = flag.String("token", "", "Service identifier token")
backend = flag.String("backend", "127.0.0.1:9090", "backend TCP/HTTP server")
)
func main() {
flag.Parse()
cfg := &tunnel.ClientConfig{
Identifier: *token,
LocalAddr: *backend,
ServerAddr: "127.0.0.1:9234",
}
client, err := tunnel.NewClient(cfg)
if err != nil {
log.Fatal(err)
}
client.Start()
}

253
main.go Normal file
View File

@ -0,0 +1,253 @@
package main
import (
"crypto/x509"
"encoding/pem"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"math/rand"
"net"
"net/http"
"net/rpc"
"os"
"path/filepath"
"strconv"
"time"
"git.xeserv.us/xena/route/routerpc"
r "github.com/GoRethink/gorethink"
"github.com/Xe/uuid"
"github.com/Yawning/bulb"
"github.com/facebookgo/flagenv"
_ "github.com/joho/godotenv/autoload"
"github.com/koding/tunnel"
"github.com/sycamoreone/orc/tor"
)
var (
rethinkDBHost = flag.String("rethink-host", "", "RethinkDB host")
rethinkDBDatabase = flag.String("rethink-database", "", "RethinkDB database")
controlKeyFile = flag.String("control-key-file", "", "Control host keyfile")
controlHost = flag.String("control-host", "", "Control host onion hash")
torDataDir = flag.String("tor-data-dir", "./var", "Tor data directory")
torHashedPassword = flag.String("tor-hashed-password", "", "Tor hashed password")
torPassword = flag.String("tor-password", "hunter2", "Tor clear password")
webPort = flag.String("web-port", "9234", "HTTP ingress port for backends and users")
)
// RPC constants
const (
RPCPort uint16 = 39453
)
func main() {
flag.Parse()
flagenv.Parse()
rand.Seed(time.Now().Unix())
s, err := create(&ServerConfig{
ControlHost: *controlHost,
ControlKeyFile: *controlKeyFile,
RethinkDBHost: *rethinkDBHost,
RethinkDBDatabase: *rethinkDBDatabase,
TorDataDir: *torDataDir,
TorHashedPassword: *torHashedPassword,
TorPassword: *torPassword,
})
if err != nil {
log.Fatal(err)
}
l, err := net.Listen("tcp", "127.0.0.1:"+*webPort)
if err != nil {
log.Fatal(err)
}
defer l.Close()
hs := &http.Server{
Handler: s,
Addr: "127.0.0.1:" + *webPort,
}
hs.Serve(l)
}
// Server is the main server type
type Server struct {
cfg *ServerConfig
sess *r.Session
torCon *bulb.Conn
torCmd *tor.Cmd
torControlPath string
rpcS *rpc.Server
rpcAddr string
ts *tunnel.Server
}
// ServerConfig configures Server
type ServerConfig struct {
ControlHost, ControlKeyFile string
RethinkDBHost, RethinkDBDatabase string
TorDataDir, TorHashedPassword, TorPassword string
}
func create(cfg *ServerConfig) (*Server, error) {
session, err := r.Connect(r.ConnectOpts{
Address: cfg.RethinkDBHost,
Database: cfg.RethinkDBDatabase,
})
if err != nil {
return nil, err
}
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
return nil, err
}
torControlPath := filepath.Join(cfg.TorDataDir, fmt.Sprintf("%d.sock", rand.Int63()))
tc := tor.NewConfig()
tc.Set("ControlSocket", torControlPath)
tc.Set("DataDirectory", cfg.TorDataDir)
tc.Set("HashedControlPassword", cfg.TorHashedPassword)
tc.Set("SocksPort", "0")
cp := rand.Intn(64512) // 64k - 1k
tc.Set("ControlPort", cp)
tc.Timeout = 30 * time.Second
log.Println(tc.ToCmdLineFormat())
tcmd, err := tor.NewCmd(tc)
if err != nil {
return nil, err
}
err = tcmd.Start()
if err != nil {
return nil, err
}
time.Sleep(5 * time.Second)
bc, err := bulb.Dial("tcp", "127.0.0.1:"+strconv.Itoa(cp))
if err != nil {
return nil, err
}
err = bc.Authenticate(cfg.TorPassword)
if err != nil {
return nil, err
}
fin, err := os.Open(cfg.ControlKeyFile)
if err != nil {
return nil, err
}
defer fin.Close()
data, err := ioutil.ReadAll(fin)
if err != nil {
return nil, err
}
var block *pem.Block
block, _ = pem.Decode([]byte(data))
pKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
_, err = bc.AddOnion([]bulb.OnionPortSpec{
bulb.OnionPortSpec{
VirtPort: RPCPort,
Target: l.Addr().String(),
},
}, pKey, false)
if err != nil {
return nil, err
}
rpcs := rpc.NewServer()
ts, err := tunnel.NewServer(&tunnel.ServerConfig{})
if err != nil {
return nil, err
}
s := &Server{
cfg: cfg,
sess: session,
torCon: bc,
torCmd: tcmd,
torControlPath: torControlPath,
rpcS: rpcs,
rpcAddr: l.Addr().String(),
ts: ts,
}
rpcs.RegisterName("Urls", &RPCServer{Server: s})
go rpcs.Accept(l)
return s, nil
}
func (s *Server) onionPath(name string) string {
return filepath.Join(s.cfg.TorDataDir, name)
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.RequestURI == rpc.DefaultRPCPath {
s.rpcS.ServeHTTP(w, r)
return
}
s.ts.ServeHTTP(w, r)
}
type RPCServer struct {
*Server
}
func (rs *RPCServer) AddHost(req routerpc.AddHostRequest, resp *routerpc.AddHostResponse) error {
if req.APIKey != "hunter2" {
return errors.New("invalid api key")
}
token := uuid.New()
oi, err := rs.torCon.AddOnion([]bulb.OnionPortSpec{
bulb.OnionPortSpec{
VirtPort: 80,
Target: "127.0.0.1:" + *webPort,
},
}, req.PrivKey, false)
if err != nil {
return err
}
resp.Hostname = oi.OnionID + ".onion"
resp.Token = token
rs.Server.ts.AddHost(resp.Hostname, token)
if oi.PrivateKey != nil {
resp.PrivKey = oi.PrivateKey
} else {
resp.PrivKey = req.PrivKey
}
return nil
}

27
routerpc/rpc.go Normal file
View File

@ -0,0 +1,27 @@
package routerpc
import (
"crypto"
"crypto/rsa"
"encoding/gob"
)
func init() {
gob.Register(&AddHostRequest{})
gob.Register(&AddHostResponse{})
gob.Register(&rsa.PrivateKey{})
}
// AddHostRequest is for adding a host to the routing mesh
type AddHostRequest struct {
APIKey string
Hostname string
PrivKey crypto.PrivateKey
}
// AddHostResponse ...
type AddHostResponse struct {
Token string
Hostname string
PrivKey crypto.PrivateKey
}