that's pretty cool
This commit is contained in:
3
Makefile
3
Makefile
@ -76,3 +76,6 @@ vet:
|
||||
go vet ./*.go
|
||||
go vet ./httpproxy/*.go
|
||||
go vet ./windows/*.go
|
||||
|
||||
clean:
|
||||
rm -f httpproxy-*
|
||||
|
31
README.md
31
README.md
@ -1,12 +1,23 @@
|
||||
httptunnel
|
||||
==========
|
||||
i2phttpproxy
|
||||
============
|
||||
|
||||
Super simple standalone http proxy for i2p using SAM. It's mostly just a way of
|
||||
easily setting up a single-identity for a single application. It offers a single
|
||||
HTTP Proxy tunnel for a single application and is a form of isolation, but it
|
||||
isn't Tor-like isolation in that it's intended to be started by the application
|
||||
and is not based on a SOCKS proxy with extended behavior. It's tiny, it's pure
|
||||
Go, it's easy to embed in other HTTP applications requiring a client proxy, and
|
||||
the default executable is self-supervising on Unix-like plaforms. It will work
|
||||
with any i2p router that has a SAM bridge.
|
||||
This is a very simple standalone HTTP Proxy for i2p based on the SAM Bridge. It
|
||||
has a few advantages in certain situations, especially for adapting applications
|
||||
that speak HTTP to the i2p network. It allows applications to start their own
|
||||
HTTP proxies, with their own identities within i2p and their own discrete
|
||||
configurations. It also has some disadvantages, it cannot add new readable
|
||||
names to your i2p address book nor is it able to use an outproxy. It's new, but
|
||||
it should be stable enough to experiment with a Tor Browser or a hardened
|
||||
Firefox configuration.
|
||||
|
||||
It is not, and is not intended to be, and will not be intended for use by
|
||||
multiple clients at the same time. It might be more-or-less OK as part of an
|
||||
inproxy but you should only use it for one client at a time. A multi-client
|
||||
solution will also be available soon([eeProxy](https://github.com/eyedeekay/eeProxy).
|
||||
|
||||
Features: Done
|
||||
--------------
|
||||
|
||||
* Self-supervising, Self-restarting on Unixes
|
||||
* CONNECT support
|
||||
* "New Ident" signaling interface(Unix-only for now)
|
||||
|
33
httpcontroller.go
Normal file
33
httpcontroller.go
Normal file
@ -0,0 +1,33 @@
|
||||
package i2phttpproxy
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
type SAMHTTPController struct {
|
||||
}
|
||||
|
||||
func (p *SAMHTTPController) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
|
||||
err := unixRestart()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
wr.WriteHeader(http.StatusOK)
|
||||
wr.Write([]byte("200 - Restart OK!"))
|
||||
}
|
||||
|
||||
func unixRestart() error {
|
||||
path, err := os.Executable()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmnd := exec.Command(path, "-littleboss=reload")
|
||||
err = cmnd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@ -2,39 +2,116 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
import (
|
||||
. "github.com/eyedeekay/httptunnel"
|
||||
"github.com/eyedeekay/littleboss"
|
||||
)
|
||||
|
||||
var (
|
||||
tunnelName = flag.String("service-name", "sam-http-proxy", "Name of the service(can be anything)")
|
||||
samHostString = flag.String("bridge-host", "127.0.0.1", "host: of the SAM bridge")
|
||||
samPortString = flag.String("bridge-port", "7656", ":port of the SAM bridge")
|
||||
debugConnection = flag.Bool("conn-debug", false, "Print connection debug info")
|
||||
inboundTunnelLength = flag.Int("in-tun-length", 2, "Tunnel Length(default 3)")
|
||||
outboundTunnelLength = flag.Int("out-tun-length", 2, "Tunnel Length(default 3)")
|
||||
inboundTunnels = flag.Int("in-tunnels", 2, "Inbound Tunnel Count(default 8)")
|
||||
outboundTunnels = flag.Int("out-tunnels", 2, "Outbound Tunnel Count(default 8)")
|
||||
inboundBackups = flag.Int("in-backups", 1, "Inbound Backup Count(default 3)")
|
||||
outboundBackups = flag.Int("out-backups", 1, "Inbound Backup Count(default 3)")
|
||||
inboundVariance = flag.Int("in-variance", 0, "Inbound Backup Count(default 3)")
|
||||
outboundVariance = flag.Int("out-variance", 0, "Inbound Backup Count(default 3)")
|
||||
dontPublishLease = flag.Bool("no-publish", true, "Don't publish the leaseset(Client mode)")
|
||||
//encryptLease = flag.Bool("encrypt-lease", true, "Encrypt the leaseset(")
|
||||
reduceIdle = flag.Bool("reduce-idle", false, "Reduce tunnels on extended idle time")
|
||||
reduceIdleTime = flag.Int("reduce-idle-time", 2000000, "Reduce tunnels after time(Ms)")
|
||||
reduceIdleQuantity = flag.Int("reduce-idle-tunnels", 1, "Reduce tunnels to this level")
|
||||
)
|
||||
|
||||
var addr string
|
||||
|
||||
func main() {
|
||||
lb := littleboss.New("i2p-http-tunnel")
|
||||
ln := lb.Listener("http", "tcp", "127.0.0.1:7950", "The address of the proxy")
|
||||
lb := littleboss.New(*tunnelName)
|
||||
ln := lb.Listener("proxy-addr", "tcp", "127.0.0.1:7950", "The address of the proxy")
|
||||
cln := lb.Listener("control-addr", "tcp", "127.0.0.1:7951", "The address of the controller")
|
||||
lb.Run(func(ctx context.Context) {
|
||||
proxyMain(ctx, ln.Listener())
|
||||
proxyMain(ctx, ln.Listener(), cln.Listener())
|
||||
})
|
||||
}
|
||||
|
||||
func proxyMain(ctx context.Context, ln net.Listener) {
|
||||
handler, err := NewHttpProxy()
|
||||
func proxyMain(ctx context.Context, ln net.Listener, cln net.Listener) {
|
||||
flag.Parse()
|
||||
srv := &http.Server{
|
||||
ReadTimeout: 600 * time.Second,
|
||||
WriteTimeout: 600 * time.Second,
|
||||
Addr: addr,
|
||||
}
|
||||
var err error
|
||||
srv.Handler, err = NewHttpProxy(
|
||||
SetHost(*samHostString),
|
||||
SetPort(*samPortString),
|
||||
SetDebug(*debugConnection),
|
||||
SetInLength(uint(*inboundTunnelLength)),
|
||||
SetOutLength(uint(*outboundTunnelLength)),
|
||||
SetInQuantity(uint(*inboundTunnels)),
|
||||
SetOutQuantity(uint(*outboundTunnels)),
|
||||
SetInBackups(uint(*inboundBackups)),
|
||||
SetOutBackups(uint(*outboundBackups)),
|
||||
SetInVariance(*inboundVariance),
|
||||
SetOutVariance(*outboundVariance),
|
||||
SetUnpublished(*dontPublishLease),
|
||||
SetReduceIdle(*reduceIdle),
|
||||
SetReduceIdleTime(uint(*reduceIdleTime)),
|
||||
SetReduceIdleQuantity(uint(*reduceIdleQuantity)),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ctrlsrv := &http.Server{
|
||||
ReadTimeout: 600 * time.Second,
|
||||
WriteTimeout: 600 * time.Second,
|
||||
Addr: addr,
|
||||
Handler: &SAMHTTPController{},
|
||||
}
|
||||
|
||||
go func() {
|
||||
log.Println("Starting proxy server on", ln.Addr())
|
||||
if err := http.Serve(ln, handler); err != nil {
|
||||
log.Println("Starting control server on", cln.Addr())
|
||||
if err := ctrlsrv.Serve(cln); err != nil {
|
||||
if err == http.ErrServerClosed {
|
||||
return
|
||||
}
|
||||
log.Fatal("Serve:", err)
|
||||
}
|
||||
log.Println("Stopping control server on", cln.Addr())
|
||||
}()
|
||||
|
||||
log.Println("Stopping proxy server on", ln.Addr())
|
||||
go func() {
|
||||
log.Println("Starting proxy server on", ln.Addr())
|
||||
if err := srv.Serve(ln); err != nil {
|
||||
if err == http.ErrServerClosed {
|
||||
return
|
||||
}
|
||||
log.Fatal("Serve:", err)
|
||||
}
|
||||
log.Println("Stopping proxy server on", ln.Addr())
|
||||
}()
|
||||
|
||||
go counter()
|
||||
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
func counter() {
|
||||
var x int
|
||||
for {
|
||||
log.Println("Identity is", x, "minute(s) old")
|
||||
time.Sleep(1 * time.Minute)
|
||||
x++
|
||||
}
|
||||
}
|
||||
|
315
httptunnel-options.go
Normal file
315
httptunnel-options.go
Normal file
@ -0,0 +1,315 @@
|
||||
package i2phttpproxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//Option is a client Option
|
||||
type Option func(*SAMHTTPProxy) error
|
||||
|
||||
//SetAddr sets a clients's address in the form host:port or host, port
|
||||
func SetAddr(s ...string) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if len(s) == 1 {
|
||||
split := strings.SplitN(s[0], ":", 2)
|
||||
if len(split) == 2 {
|
||||
if i, err := strconv.Atoi(split[1]); err == nil {
|
||||
if i < 65536 {
|
||||
c.SamHost = split[0]
|
||||
c.SamPort = split[1]
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid port")
|
||||
}
|
||||
return fmt.Errorf("Invalid port; non-number")
|
||||
}
|
||||
return fmt.Errorf("Invalid address; use host:port %s", split)
|
||||
} else if len(s) == 2 {
|
||||
if i, err := strconv.Atoi(s[1]); err == nil {
|
||||
if i < 65536 {
|
||||
c.SamHost = s[0]
|
||||
c.SamPort = s[1]
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid port")
|
||||
}
|
||||
return fmt.Errorf("Invalid port; non-number")
|
||||
} else {
|
||||
return fmt.Errorf("Invalid address")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//SetAddrMixed sets a clients's address in the form host, port(int)
|
||||
func SetAddrMixed(s string, i int) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if i < 65536 && i > 0 {
|
||||
c.SamHost = s
|
||||
c.SamPort = strconv.Itoa(i)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid port")
|
||||
}
|
||||
}
|
||||
|
||||
//SetHost sets the host of the client's SAM bridge
|
||||
func SetHost(s string) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
c.SamHost = s
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//SetPort sets the port of the client's SAM bridge using a string
|
||||
func SetPort(s string) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
port, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Invalid port; non-number")
|
||||
}
|
||||
if port < 65536 && port > -1 {
|
||||
c.SamPort = s
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid port")
|
||||
}
|
||||
}
|
||||
|
||||
//SetPortInt sets the port of the client's SAM bridge using a string
|
||||
func SetPortInt(i int) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if i < 65536 && i > -1 {
|
||||
c.SamPort = strconv.Itoa(i)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid port")
|
||||
}
|
||||
}
|
||||
|
||||
//SetDebug enables debugging messages
|
||||
func SetDebug(b bool) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
c.debug = b
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//SetInLength sets the number of hops inbound
|
||||
func SetInLength(u uint) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if u < 7 {
|
||||
c.inLength = u
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid inbound tunnel length")
|
||||
}
|
||||
}
|
||||
|
||||
//SetOutLength sets the number of hops outbound
|
||||
func SetOutLength(u uint) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if u < 7 {
|
||||
c.outLength = u
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid outbound tunnel length")
|
||||
}
|
||||
}
|
||||
|
||||
//SetInVariance sets the variance of a number of hops inbound
|
||||
func SetInVariance(i int) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if i < 7 && i > -7 {
|
||||
c.inVariance = i
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid inbound tunnel length")
|
||||
}
|
||||
}
|
||||
|
||||
//SetOutVariance sets the variance of a number of hops outbound
|
||||
func SetOutVariance(i int) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if i < 7 && i > -7 {
|
||||
c.outVariance = i
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid outbound tunnel variance")
|
||||
}
|
||||
}
|
||||
|
||||
//SetInQuantity sets the inbound tunnel quantity
|
||||
func SetInQuantity(u uint) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if u <= 16 {
|
||||
c.inQuantity = u
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid inbound tunnel quantity")
|
||||
}
|
||||
}
|
||||
|
||||
//SetOutQuantity sets the outbound tunnel quantity
|
||||
func SetOutQuantity(u uint) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if u <= 16 {
|
||||
c.outQuantity = u
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid outbound tunnel quantity")
|
||||
}
|
||||
}
|
||||
|
||||
//SetInBackups sets the inbound tunnel backups
|
||||
func SetInBackups(u uint) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if u < 6 {
|
||||
c.inBackups = u
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid inbound tunnel backup quantity")
|
||||
}
|
||||
}
|
||||
|
||||
//SetOutBackups sets the inbound tunnel backups
|
||||
func SetOutBackups(u uint) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if u < 6 {
|
||||
c.outBackups = u
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid outbound tunnel backup quantity")
|
||||
}
|
||||
}
|
||||
|
||||
//SetUnpublished tells the router to not publish the client leaseset
|
||||
func SetUnpublished(b bool) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
c.dontPublishLease = b
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//SetEncrypt tells the router to use an encrypted leaseset
|
||||
func SetEncrypt(b bool) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
c.encryptLease = b
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//SetReduceIdle sets the created tunnels to be reduced during extended idle time to avoid excessive resource usage
|
||||
func SetReduceIdle(b bool) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
c.reduceIdle = b
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//SetReduceIdleTime sets time to wait before the tunnel quantity is reduced
|
||||
func SetReduceIdleTime(u uint) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if u > 300000 {
|
||||
c.reduceIdleTime = u
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid reduce idle time %v", u)
|
||||
}
|
||||
}
|
||||
|
||||
//SetReduceIdleQuantity sets number of tunnels to keep alive during an extended idle period
|
||||
func SetReduceIdleQuantity(u uint) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if u < 5 {
|
||||
c.reduceIdleQuantity = u
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid reduced tunnel quantity %v", u)
|
||||
}
|
||||
}
|
||||
|
||||
//SetCompression sets the tunnels to close after a specific amount of time
|
||||
func SetCompression(b bool) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
c.compression = b
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//return the inbound length as a string.
|
||||
func (c *SAMHTTPProxy) inlength() string {
|
||||
return fmt.Sprintf("inbound.length=%d", c.inLength)
|
||||
}
|
||||
|
||||
//return the outbound length as a string.
|
||||
func (c *SAMHTTPProxy) outlength() string {
|
||||
return fmt.Sprintf("outbound.length=%d", c.outLength)
|
||||
}
|
||||
|
||||
//return the inbound length variance as a string.
|
||||
func (c *SAMHTTPProxy) invariance() string {
|
||||
return fmt.Sprintf("inbound.lengthVariance=%d", c.inVariance)
|
||||
}
|
||||
|
||||
//return the outbound length variance as a string.
|
||||
func (c *SAMHTTPProxy) outvariance() string {
|
||||
return fmt.Sprintf("outbound.lengthVariance=%d", c.outVariance)
|
||||
}
|
||||
|
||||
//return the inbound tunnel quantity as a string.
|
||||
func (c *SAMHTTPProxy) inquantity() string {
|
||||
return fmt.Sprintf("inbound.quantity=%d", c.inQuantity)
|
||||
}
|
||||
|
||||
//return the outbound tunnel quantity as a string.
|
||||
func (c *SAMHTTPProxy) outquantity() string {
|
||||
return fmt.Sprintf("outbound.quantity=%d", c.outQuantity)
|
||||
}
|
||||
|
||||
//return the inbound tunnel quantity as a string.
|
||||
func (c *SAMHTTPProxy) inbackups() string {
|
||||
return fmt.Sprintf("inbound.backupQuantity=%d", c.inQuantity)
|
||||
}
|
||||
|
||||
//return the outbound tunnel quantity as a string.
|
||||
func (c *SAMHTTPProxy) outbackups() string {
|
||||
return fmt.Sprintf("outbound.backupQuantity=%d", c.outQuantity)
|
||||
}
|
||||
|
||||
func (c *SAMHTTPProxy) encryptlease() string {
|
||||
if c.encryptLease {
|
||||
return "i2cp.encryptLeaseSet=true"
|
||||
}
|
||||
return "i2cp.encryptLeaseSet=false"
|
||||
}
|
||||
|
||||
func (c *SAMHTTPProxy) dontpublishlease() string {
|
||||
if c.dontPublishLease {
|
||||
return "i2cp.dontPublishLeaseSet=true"
|
||||
}
|
||||
return "i2cp.dontPublishLeaseSet=false"
|
||||
}
|
||||
|
||||
func (c *SAMHTTPProxy) reduceonidle() string {
|
||||
if c.reduceIdle {
|
||||
return "i2cp.reduceOnIdle=true"
|
||||
}
|
||||
return "i2cp.reduceOnIdle=false"
|
||||
}
|
||||
|
||||
func (c *SAMHTTPProxy) reduceidletime() string {
|
||||
return fmt.Sprintf("i2cp.reduceIdleTime=%d", c.reduceIdleTime)
|
||||
}
|
||||
|
||||
func (c *SAMHTTPProxy) reduceidlecount() string {
|
||||
return fmt.Sprintf("i2cp.reduceIdleQuantity=%d", c.reduceIdleQuantity)
|
||||
}
|
||||
|
||||
func (c *SAMHTTPProxy) compresion() string {
|
||||
if c.compression {
|
||||
return "i2cp.gzip=true"
|
||||
}
|
||||
return "i2cp.gzip=false"
|
||||
}
|
193
httptunnel.go
193
httptunnel.go
@ -11,8 +11,36 @@ import (
|
||||
|
||||
import (
|
||||
"github.com/eyedeekay/goSam"
|
||||
"github.com/eyedeekay/sam3"
|
||||
)
|
||||
|
||||
type SAMHTTPProxy struct {
|
||||
gosam *goSam.Client
|
||||
Client *http.Client
|
||||
samcon *sam3.SAM
|
||||
keys sam3.I2PKeys
|
||||
stream *sam3.StreamSession
|
||||
SamHost string
|
||||
SamPort string
|
||||
TunName string
|
||||
inLength uint
|
||||
outLength uint
|
||||
inVariance int
|
||||
outVariance int
|
||||
inQuantity uint
|
||||
outQuantity uint
|
||||
inBackups uint
|
||||
outBackups uint
|
||||
dontPublishLease bool
|
||||
encryptLease bool
|
||||
reduceIdle bool
|
||||
reduceIdleTime uint
|
||||
reduceIdleQuantity uint
|
||||
compression bool
|
||||
|
||||
debug bool
|
||||
}
|
||||
|
||||
func copyHeader(dst, src http.Header) {
|
||||
for k, vv := range src {
|
||||
for _, v := range vv {
|
||||
@ -38,15 +66,10 @@ func delHopHeaders(header http.Header) {
|
||||
}
|
||||
}
|
||||
|
||||
type Proxy struct {
|
||||
Sam *goSam.Client
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
func (p *Proxy) freshClient() *http.Client {
|
||||
func (p *SAMHTTPProxy) freshClient() *http.Client {
|
||||
return &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: p.Sam.Dial,
|
||||
Dial: p.gosam.Dial,
|
||||
MaxIdleConns: 0,
|
||||
MaxIdleConnsPerHost: 3,
|
||||
DisableKeepAlives: false,
|
||||
@ -62,7 +85,7 @@ func (p *Proxy) freshClient() *http.Client {
|
||||
|
||||
}
|
||||
|
||||
func (p *Proxy) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
|
||||
func (p *SAMHTTPProxy) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
|
||||
log.Println(req.RemoteAddr, " ", req.Method, " ", req.URL)
|
||||
|
||||
if req.URL.Scheme != "http" && req.URL.Scheme != "https" && !strings.HasSuffix(req.URL.Host, ".i2p") {
|
||||
@ -72,14 +95,44 @@ func (p *Proxy) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
req.RequestURI = ""
|
||||
if req.Method == http.MethodConnect {
|
||||
log.Println("Connecting tunnel")
|
||||
p.connect(wr, req)
|
||||
} else {
|
||||
req.RequestURI = ""
|
||||
delHopHeaders(req.Header)
|
||||
p.get(wr, req)
|
||||
}
|
||||
|
||||
delHopHeaders(req.Header)
|
||||
|
||||
p.get(wr, req)
|
||||
}
|
||||
|
||||
func (p *Proxy) get(wr http.ResponseWriter, req *http.Request) {
|
||||
func (p *SAMHTTPProxy) connect(wr http.ResponseWriter, req *http.Request) {
|
||||
dest_conn, err := p.stream.Dial("tcp", req.Host)
|
||||
if err != nil {
|
||||
http.Error(wr, err.Error(), http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
wr.WriteHeader(http.StatusOK)
|
||||
hijacker, ok := wr.(http.Hijacker)
|
||||
if !ok {
|
||||
http.Error(wr, "Hijacking not supported", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
client_conn, _, err := hijacker.Hijack()
|
||||
if err != nil {
|
||||
http.Error(wr, err.Error(), http.StatusServiceUnavailable)
|
||||
}
|
||||
go transfer(dest_conn, client_conn)
|
||||
go transfer(client_conn, dest_conn)
|
||||
}
|
||||
|
||||
func transfer(destination io.WriteCloser, source io.ReadCloser) {
|
||||
defer destination.Close()
|
||||
defer source.Close()
|
||||
io.Copy(destination, source)
|
||||
}
|
||||
|
||||
func (p *SAMHTTPProxy) get(wr http.ResponseWriter, req *http.Request) {
|
||||
Client := p.freshClient()
|
||||
resp, err := Client.Do(req)
|
||||
if err != nil {
|
||||
@ -92,38 +145,92 @@ func (p *Proxy) get(wr http.ResponseWriter, req *http.Request) {
|
||||
io.Copy(wr, resp.Body)
|
||||
}
|
||||
|
||||
func NewHttpProxy() (*Proxy, error) {
|
||||
sam, err := goSam.NewClientFromOptions(
|
||||
goSam.SetHost("127.0.0.1"),
|
||||
goSam.SetPort("7656"),
|
||||
goSam.SetUnpublished(true),
|
||||
goSam.SetInLength(uint(2)),
|
||||
goSam.SetOutLength(uint(2)),
|
||||
goSam.SetInQuantity(uint(4)),
|
||||
goSam.SetOutQuantity(uint(4)),
|
||||
goSam.SetInBackups(uint(2)),
|
||||
goSam.SetOutBackups(uint(2)),
|
||||
goSam.SetReduceIdle(true),
|
||||
goSam.SetReduceIdleTime(uint(2000000)),
|
||||
func (p *SAMHTTPProxy) sam3Args() []string {
|
||||
return []string{
|
||||
p.inlength(),
|
||||
p.outlength(),
|
||||
p.invariance(),
|
||||
p.outvariance(),
|
||||
p.inquantity(),
|
||||
p.outquantity(),
|
||||
p.inbackups(),
|
||||
p.outbackups(),
|
||||
p.dontpublishlease(),
|
||||
p.encryptlease(),
|
||||
p.reduceonidle(),
|
||||
p.reduceidletime(),
|
||||
p.reduceidlecount(),
|
||||
"i2cp.gzip=true",
|
||||
}
|
||||
}
|
||||
|
||||
func NewHttpProxy(opts ...func(*SAMHTTPProxy) error) (*SAMHTTPProxy, error) {
|
||||
var handler SAMHTTPProxy
|
||||
handler.SamHost = "127.0.0.1"
|
||||
handler.SamPort = "7656"
|
||||
handler.TunName = "sam-http-proxy"
|
||||
handler.inLength = 2
|
||||
handler.outLength = 2
|
||||
handler.inVariance = 0
|
||||
handler.outVariance = 0
|
||||
handler.inQuantity = 1
|
||||
handler.outQuantity = 1
|
||||
handler.inBackups = 1
|
||||
handler.outBackups = 1
|
||||
handler.dontPublishLease = true
|
||||
handler.encryptLease = false
|
||||
handler.reduceIdle = false
|
||||
handler.reduceIdleTime = 2000000
|
||||
handler.reduceIdleQuantity = 1
|
||||
for _, o := range opts {
|
||||
if err := o(&handler); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var err error
|
||||
handler.gosam, err = goSam.NewClientFromOptions(
|
||||
goSam.SetHost(handler.SamHost),
|
||||
goSam.SetPort(handler.SamPort),
|
||||
goSam.SetUnpublished(handler.dontPublishLease),
|
||||
goSam.SetInLength(handler.inLength),
|
||||
goSam.SetOutLength(handler.outLength),
|
||||
goSam.SetInQuantity(handler.inQuantity),
|
||||
goSam.SetOutQuantity(handler.outQuantity),
|
||||
goSam.SetInBackups(handler.inBackups),
|
||||
goSam.SetOutBackups(handler.outBackups),
|
||||
goSam.SetReduceIdle(handler.reduceIdle),
|
||||
goSam.SetReduceIdleTime(handler.reduceIdleTime),
|
||||
goSam.SetReduceIdleQuantity(handler.reduceIdleQuantity),
|
||||
)
|
||||
return nil, err
|
||||
handler := Proxy{
|
||||
Sam: sam,
|
||||
Client: &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: sam.Dial,
|
||||
MaxIdleConns: 0,
|
||||
MaxIdleConnsPerHost: 3,
|
||||
DisableKeepAlives: false,
|
||||
ResponseHeaderTimeout: time.Second * 600,
|
||||
ExpectContinueTimeout: time.Second * 600,
|
||||
IdleConnTimeout: time.Second * 600,
|
||||
TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
CheckRedirect: nil,
|
||||
Timeout: time.Second * 600,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
handler.samcon, err = sam3.NewSAM(handler.SamHost + ":" + handler.SamPort)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
handler.keys, err = handler.samcon.NewKeys()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
handler.stream, err = handler.samcon.NewStreamSession("sam-http-connector", handler.keys, handler.sam3Args())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
handler.Client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: handler.gosam.Dial,
|
||||
MaxIdleConns: 0,
|
||||
MaxIdleConnsPerHost: 3,
|
||||
DisableKeepAlives: false,
|
||||
ResponseHeaderTimeout: time.Second * 600,
|
||||
ExpectContinueTimeout: time.Second * 600,
|
||||
IdleConnTimeout: time.Second * 600,
|
||||
//TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
|
||||
//TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
CheckRedirect: nil,
|
||||
Timeout: time.Second * 600,
|
||||
}
|
||||
return &handler, nil
|
||||
}
|
||||
|
@ -4,19 +4,79 @@ import (
|
||||
"flag"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
import (
|
||||
. "github.com/eyedeekay/httptunnel"
|
||||
)
|
||||
|
||||
var (
|
||||
//tunnelName = flag.String("service-name", "sam-http-proxy", "Name of the service(can be anything)")
|
||||
samHostString = flag.String("bridge-host", "127.0.0.1", "host: of the SAM bridge")
|
||||
samPortString = flag.String("bridge-port", "7656", ":port of the SAM bridge")
|
||||
proxHostString = flag.String("proxy-host", "127.0.0.1", "host: of the HTTP proxy")
|
||||
proxPortString = flag.String("proxy-port", "7950", ":port of the HTTP proxy")
|
||||
debugConnection = flag.Bool("conn-debug", false, "Print connection debug info")
|
||||
inboundTunnelLength = flag.Int("in-tun-length", 3, "Tunnel Length(default 3)")
|
||||
outboundTunnelLength = flag.Int("out-tun-length", 3, "Tunnel Length(default 3)")
|
||||
inboundTunnels = flag.Int("in-tunnels", 4, "Inbound Tunnel Count(default 8)")
|
||||
outboundTunnels = flag.Int("out-tunnels", 2, "Outbound Tunnel Count(default 8)")
|
||||
inboundBackups = flag.Int("in-backups", 3, "Inbound Backup Count(default 3)")
|
||||
outboundBackups = flag.Int("out-backups", 3, "Inbound Backup Count(default 3)")
|
||||
inboundVariance = flag.Int("in-variance", 3, "Inbound Backup Count(default 3)")
|
||||
outboundVariance = flag.Int("out-variance", 3, "Inbound Backup Count(default 3)")
|
||||
dontPublishLease = flag.Bool("no-publish", true, "Don't publish the leaseset(Client mode)")
|
||||
//encryptLease = flag.Bool("encrypt-lease", true, "Encrypt the leaseset(")
|
||||
reduceIdle = flag.Bool("reduce-idle", false, "Reduce tunnels on extended idle time")
|
||||
reduceIdleTime = flag.Int("reduce-idle-time", 2000000, "Reduce tunnels after time(Ms)")
|
||||
reduceIdleQuantity = flag.Int("reduce-idle-tunnels", 1, "Reduce tunnels to this level")
|
||||
)
|
||||
|
||||
func main() {
|
||||
var addr = flag.String("addr", "127.0.0.1:7950", "The addr of the application.")
|
||||
flag.Parse()
|
||||
addr := *proxHostString + ":" + *proxPortString
|
||||
|
||||
handler, err := NewHttpProxy()
|
||||
srv := &http.Server{
|
||||
ReadTimeout: 600 * time.Second,
|
||||
WriteTimeout: 600 * time.Second,
|
||||
Addr: addr,
|
||||
}
|
||||
var err error
|
||||
srv.Handler, err = NewHttpProxy(
|
||||
SetHost(*samHostString),
|
||||
SetPort(*samPortString),
|
||||
SetDebug(*debugConnection),
|
||||
SetInLength(uint(*inboundTunnelLength)),
|
||||
SetOutLength(uint(*outboundTunnelLength)),
|
||||
SetInQuantity(uint(*inboundTunnels)),
|
||||
SetOutQuantity(uint(*outboundTunnels)),
|
||||
SetInBackups(uint(*inboundBackups)),
|
||||
SetOutBackups(uint(*outboundBackups)),
|
||||
SetInVariance(*inboundVariance),
|
||||
SetOutVariance(*outboundVariance),
|
||||
SetUnpublished(*dontPublishLease),
|
||||
SetReduceIdle(*reduceIdle),
|
||||
SetReduceIdleTime(uint(*reduceIdleTime)),
|
||||
SetReduceIdleQuantity(uint(*reduceIdleQuantity)),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Println("Starting proxy server on", *addr)
|
||||
if err := http.ListenAndServe(*addr, handler); err != nil {
|
||||
go counter()
|
||||
|
||||
log.Println("Starting proxy server on", addr)
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
log.Fatal("ListenAndServe:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func counter() {
|
||||
var x int
|
||||
for {
|
||||
log.Println("Identity is", x, "minute(s) old")
|
||||
time.Sleep(1 * time.Minute)
|
||||
x++
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user