move some stuff to common
This commit is contained in:
12
Makefile
12
Makefile
@ -15,8 +15,9 @@ win64:
|
||||
GOOS=windows GOARCH=amd64 go build \
|
||||
$(GO_COMPILER_OPTS) \
|
||||
-buildmode=exe \
|
||||
-o ./httproxy.exe \
|
||||
-o ./httpproxy.exe \
|
||||
./windows/main.go
|
||||
@echo "built"
|
||||
|
||||
win32:
|
||||
GOOS=windows GOARCH=386 go build \
|
||||
@ -24,6 +25,7 @@ win32:
|
||||
-buildmode=exe \
|
||||
-o ./httpproxy.exe \
|
||||
./windows/main.go
|
||||
@echo "built"
|
||||
|
||||
lin: lin64 lin32
|
||||
|
||||
@ -32,6 +34,7 @@ lin64:
|
||||
$(GO_COMPILER_OPTS) \
|
||||
-o ./httpproxy-64 \
|
||||
./httpproxy/main.go
|
||||
@echo "built"
|
||||
|
||||
lin32:
|
||||
GOOS=linux GOARCH=386 go build \
|
||||
@ -39,6 +42,7 @@ lin32:
|
||||
-buildmode=exe \
|
||||
-o ./httpproxy-32 \
|
||||
./httpproxy/main.go
|
||||
@echo "built"
|
||||
|
||||
linarm: linarm32 linarm64
|
||||
|
||||
@ -48,6 +52,7 @@ linarm64:
|
||||
-buildmode=exe \
|
||||
-o ./httpproxy-arm64 \
|
||||
./httpproxy/main.go
|
||||
@echo "built"
|
||||
|
||||
linarm32:
|
||||
GOOS=linux GOARCH=arm go build \
|
||||
@ -55,6 +60,7 @@ linarm32:
|
||||
-buildmode=exe \
|
||||
-o ./httpproxy-arm32 \
|
||||
./httpproxy/main.go
|
||||
@echo "built"
|
||||
|
||||
|
||||
mac: mac32 mac64
|
||||
@ -64,12 +70,14 @@ mac64:
|
||||
$(GO_COMPILER_OPTS) \
|
||||
-o ./httpproxy-64.app \
|
||||
./httpproxy/main.go
|
||||
@echo "built"
|
||||
|
||||
mac32:
|
||||
GOOS=darwin GOARCH=amd64 go build \
|
||||
$(GO_COMPILER_OPTS) \
|
||||
-o ./httpproxy-32.app \
|
||||
./httpproxy/main.go
|
||||
@echo "built"
|
||||
|
||||
vet:
|
||||
go vet ./*.go
|
||||
@ -77,4 +85,4 @@ vet:
|
||||
go vet ./windows/*.go
|
||||
|
||||
clean:
|
||||
rm -f httpproxy-*
|
||||
rm -f httpproxy-* *.exe *.log
|
||||
|
10
README.md
10
README.md
@ -1,6 +1,8 @@
|
||||
i2phttpproxy
|
||||
============
|
||||
|
||||
**This is *way* more useful than it is tested. Please be careful.**
|
||||
|
||||
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
|
||||
@ -15,6 +17,9 @@ 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)).
|
||||
|
||||
This is not something you should use without understanding. It is also not
|
||||
terribly hard to understand.
|
||||
|
||||
Features: Done
|
||||
--------------
|
||||
|
||||
@ -22,3 +27,8 @@ Features: Done
|
||||
* CONNECT support
|
||||
* "New Ident" signaling interface(Unix-only for now)(I guess I might have done
|
||||
for Windows too now but I haven't tried it out yet).
|
||||
|
||||
Features: Planned
|
||||
-----------------
|
||||
|
||||
* Outproxy Support
|
||||
|
45
common/common.go
Normal file
45
common/common.go
Normal file
@ -0,0 +1,45 @@
|
||||
package proxycommon
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var hopHeaders = []string{
|
||||
"Accept-Language",
|
||||
"Connection",
|
||||
"Keep-Alive",
|
||||
"Proxy-Authenticate",
|
||||
"Proxy-Authorization",
|
||||
"Proxy-Connection",
|
||||
"Te", // canonicalized version of "TE"
|
||||
"Trailers",
|
||||
"Transfer-Encoding",
|
||||
"Upgrade",
|
||||
"X-Forwarded-For",
|
||||
}
|
||||
|
||||
func Transfer(destination io.WriteCloser, source io.ReadCloser) {
|
||||
defer destination.Close()
|
||||
defer source.Close()
|
||||
log.Println("connecting connection")
|
||||
io.Copy(destination, source)
|
||||
}
|
||||
|
||||
func DelHopHeaders(header http.Header) {
|
||||
for _, h := range hopHeaders {
|
||||
header.Del(h)
|
||||
}
|
||||
if header.Get("User-Agent") != "MYOB/6.66 (AN/ON)" {
|
||||
header.Set("User-Agent", "MYOB/6.66 (AN/ON)")
|
||||
}
|
||||
}
|
||||
|
||||
func CopyHeader(dst, src http.Header) {
|
||||
for k, vv := range src {
|
||||
for _, v := range vv {
|
||||
dst.Add(k, v)
|
||||
}
|
||||
}
|
||||
}
|
@ -11,7 +11,8 @@ import (
|
||||
)
|
||||
|
||||
import (
|
||||
. "github.com/eyedeekay/httptunnel"
|
||||
//. "github.com/eyedeekay/httptunnel"
|
||||
. ".."
|
||||
"github.com/eyedeekay/littleboss"
|
||||
)
|
||||
|
||||
@ -30,10 +31,13 @@ var (
|
||||
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")
|
||||
encryptLease = flag.Bool("encrypt-lease", false, "Encrypt the leaseset(default false, inert)")
|
||||
reduceIdle = flag.Bool("reduce-idle", false, "Reduce tunnels on extended idle time")
|
||||
closeIdle = flag.Bool("close-idle", false, "Close tunnels on extended idle time")
|
||||
closeIdleTime = flag.Int("close-idle-time", 3000000, "Reduce tunnels after time(Ms)")
|
||||
useCompression = flag.Bool("use-compression", true, "Enable gzip compression")
|
||||
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
|
||||
@ -54,7 +58,7 @@ func proxyMain(ctx context.Context, ln net.Listener, cln net.Listener) {
|
||||
srv := &http.Server{
|
||||
ReadTimeout: 600 * time.Second,
|
||||
WriteTimeout: 600 * time.Second,
|
||||
Addr: addr,
|
||||
Addr: ln.Addr().String(),
|
||||
}
|
||||
var err error
|
||||
srv.Handler, err = NewHttpProxy(
|
||||
@ -71,17 +75,20 @@ func proxyMain(ctx context.Context, ln net.Listener, cln net.Listener) {
|
||||
SetOutVariance(*outboundVariance),
|
||||
SetUnpublished(*dontPublishLease),
|
||||
SetReduceIdle(*reduceIdle),
|
||||
SetCompression(*useCompression),
|
||||
SetReduceIdleTime(uint(*reduceIdleTime)),
|
||||
SetReduceIdleQuantity(uint(*reduceIdleQuantity)),
|
||||
SetCloseIdle(*closeIdle),
|
||||
SetCloseIdleTime(uint(*closeIdleTime)),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
ctrlsrv := &http.Server{
|
||||
ReadTimeout: 600 * time.Second,
|
||||
WriteTimeout: 600 * time.Second,
|
||||
Addr: addr,
|
||||
ReadHeaderTimeout: 600 * time.Second,
|
||||
WriteTimeout: 600 * time.Second,
|
||||
Addr: cln.Addr().String(),
|
||||
}
|
||||
ctrlsrv.Handler, err = NewSAMHTTPController(profiles, nil)
|
||||
|
||||
|
@ -25,7 +25,7 @@ func SetAddr(s ...string) func(*SAMHTTPProxy) error {
|
||||
}
|
||||
return fmt.Errorf("Invalid port; non-number")
|
||||
}
|
||||
return fmt.Errorf("Invalid address; use host:port %s", split)
|
||||
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 {
|
||||
@ -238,6 +238,25 @@ func SetCompression(b bool) func(*SAMHTTPProxy) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetCloseIdle enables debugging messages
|
||||
func SetCloseIdle(b bool) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
c.closeIdle = b
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//SetCloseIdleTime sets time to wait before the tunnel quantity is reduced
|
||||
func SetCloseIdleTime(u uint) func(*SAMHTTPProxy) error {
|
||||
return func(c *SAMHTTPProxy) error {
|
||||
if u > 300000 {
|
||||
c.closeIdleTime = u
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid reduce idle time %v", u)
|
||||
}
|
||||
}
|
||||
|
||||
//return the inbound length as a string.
|
||||
func (c *SAMHTTPProxy) inlength() string {
|
||||
return fmt.Sprintf("inbound.length=%d", c.inLength)
|
||||
@ -307,9 +326,20 @@ func (c *SAMHTTPProxy) reduceidlecount() string {
|
||||
return fmt.Sprintf("i2cp.reduceIdleQuantity=%d", c.reduceIdleQuantity)
|
||||
}
|
||||
|
||||
func (c *SAMHTTPProxy) compresion() string {
|
||||
func (c *SAMHTTPProxy) usecompresion() string {
|
||||
if c.compression {
|
||||
return "i2cp.gzip=true"
|
||||
}
|
||||
return "i2cp.gzip=false"
|
||||
}
|
||||
|
||||
func (c *SAMHTTPProxy) closeonidle() string {
|
||||
if c.reduceIdle {
|
||||
return "i2cp.closeOnIdle=true"
|
||||
}
|
||||
return "i2cp.closeOnIdle=false"
|
||||
}
|
||||
|
||||
func (c *SAMHTTPProxy) closeidletime() string {
|
||||
return fmt.Sprintf("i2cp.closeIdleTime=%d", c.reduceIdleTime)
|
||||
}
|
||||
|
165
httptunnel.go
165
httptunnel.go
@ -1,7 +1,7 @@
|
||||
package i2phttpproxy
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
//"crypto/tls"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
@ -11,18 +11,14 @@ import (
|
||||
|
||||
import (
|
||||
"github.com/eyedeekay/goSam"
|
||||
"github.com/eyedeekay/sam3"
|
||||
"github.com/eyedeekay/httptunnel/common"
|
||||
)
|
||||
|
||||
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
|
||||
@ -36,36 +32,15 @@ type SAMHTTPProxy struct {
|
||||
reduceIdle bool
|
||||
reduceIdleTime uint
|
||||
reduceIdleQuantity uint
|
||||
closeIdle bool
|
||||
closeIdleTime uint
|
||||
compression bool
|
||||
|
||||
useOutProxy bool
|
||||
|
||||
debug bool
|
||||
}
|
||||
|
||||
func copyHeader(dst, src http.Header) {
|
||||
for k, vv := range src {
|
||||
for _, v := range vv {
|
||||
dst.Add(k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var hopHeaders = []string{
|
||||
"Proxy-Authenticate",
|
||||
"Proxy-Authorization",
|
||||
"Proxy-Connection",
|
||||
"X-Forwarded-For",
|
||||
"Accept-Language",
|
||||
}
|
||||
|
||||
func delHopHeaders(header http.Header) {
|
||||
for _, h := range hopHeaders {
|
||||
header.Del(h)
|
||||
}
|
||||
if header.Get("User-Agent") != "MYOB/6.66 (AN/ON)" {
|
||||
header.Set("User-Agent", "MYOB/6.66 (AN/ON)")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *SAMHTTPProxy) freshClient() *http.Client {
|
||||
return &http.Client{
|
||||
Transport: &http.Transport{
|
||||
@ -76,38 +51,65 @@ func (p *SAMHTTPProxy) freshClient() *http.Client {
|
||||
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},
|
||||
//TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
|
||||
//TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
CheckRedirect: nil,
|
||||
Timeout: time.Second * 600,
|
||||
CheckRedirect: nil,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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") {
|
||||
msg := "unsupported protocal scheme " + req.URL.Scheme
|
||||
if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
|
||||
if !(req.Method == http.MethodConnect) {
|
||||
msg := "Unsupported protocol scheme " + req.URL.Scheme
|
||||
http.Error(wr, msg, http.StatusBadRequest)
|
||||
log.Println(msg)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Println(req.URL.Host)
|
||||
|
||||
if !strings.HasSuffix(req.URL.Host, ".i2p") {
|
||||
msg := "Unsupported host " + req.URL.Host
|
||||
http.Error(wr, msg, http.StatusBadRequest)
|
||||
log.Println(msg)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Method == http.MethodConnect {
|
||||
log.Println("Connecting tunnel")
|
||||
p.connect(wr, req)
|
||||
return
|
||||
} else {
|
||||
req.RequestURI = ""
|
||||
delHopHeaders(req.Header)
|
||||
p.get(wr, req)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (p *SAMHTTPProxy) get(wr http.ResponseWriter, req *http.Request) {
|
||||
req.RequestURI = ""
|
||||
proxycommon.DelHopHeaders(req.Header)
|
||||
resp, err := p.Client.Do(req)
|
||||
if err != nil {
|
||||
msg := "Proxy Error " + err.Error()
|
||||
http.Error(wr, msg, http.StatusBadRequest)
|
||||
log.Println(msg)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
proxycommon.CopyHeader(wr.Header(), resp.Header)
|
||||
wr.WriteHeader(resp.StatusCode)
|
||||
io.Copy(wr, resp.Body)
|
||||
}
|
||||
|
||||
func (p *SAMHTTPProxy) connect(wr http.ResponseWriter, req *http.Request) {
|
||||
dest_conn, err := p.stream.Dial("tcp", req.Host)
|
||||
log.Println("CONNECT via i2p to", req.URL.Host)
|
||||
dest_conn, err := p.gosam.Dial("tcp", req.URL.Host)
|
||||
if err != nil {
|
||||
http.Error(wr, err.Error(), http.StatusServiceUnavailable)
|
||||
return
|
||||
@ -121,67 +123,32 @@ func (p *SAMHTTPProxy) connect(wr http.ResponseWriter, req *http.Request) {
|
||||
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 {
|
||||
log.Println("ServeHTTP:", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wr.WriteHeader(resp.StatusCode)
|
||||
io.Copy(wr, resp.Body)
|
||||
}
|
||||
|
||||
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",
|
||||
}
|
||||
go proxycommon.Transfer(dest_conn, client_conn)
|
||||
go proxycommon.Transfer(client_conn, dest_conn)
|
||||
}
|
||||
|
||||
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.inQuantity = 2
|
||||
handler.outQuantity = 2
|
||||
handler.inBackups = 1
|
||||
handler.outBackups = 1
|
||||
handler.dontPublishLease = true
|
||||
handler.encryptLease = false
|
||||
handler.reduceIdle = false
|
||||
handler.reduceIdleTime = 2000000
|
||||
handler.closeIdleTime = 3000000
|
||||
handler.reduceIdleQuantity = 1
|
||||
handler.useOutProxy = false
|
||||
handler.compression = true
|
||||
for _, o := range opts {
|
||||
if err := o(&handler); err != nil {
|
||||
return nil, err
|
||||
@ -201,36 +168,14 @@ func NewHttpProxy(opts ...func(*SAMHTTPProxy) error) (*SAMHTTPProxy, error) {
|
||||
goSam.SetReduceIdle(handler.reduceIdle),
|
||||
goSam.SetReduceIdleTime(handler.reduceIdleTime),
|
||||
goSam.SetReduceIdleQuantity(handler.reduceIdleQuantity),
|
||||
goSam.SetCloseIdle(handler.closeIdle),
|
||||
goSam.SetCloseIdleTime(handler.closeIdleTime),
|
||||
goSam.SetCompression(handler.compression),
|
||||
goSam.SetDebug(handler.debug),
|
||||
)
|
||||
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,
|
||||
}
|
||||
handler.Client = handler.freshClient()
|
||||
return &handler, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user