goproxy

package module
v0.0.0-...-69565b4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 17, 2017 License: BSD-3-Clause Imports: 31 Imported by: 0

README

Introduction

NOTICE: this is a fork of the original elazarl/goproxy with some radical API changes. - abourget

Package goproxy provides a customizable HTTP proxy library for Go (golang),

It supports regular HTTP proxy, HTTPS through CONNECT, "hijacking" HTTPS connection using "Man in the Middle" style attack, and SNI sniffing.

The intent of the proxy, is to be usable with reasonable amount of traffic yet, customizable and programable.

The proxy itself is simply a net/http handler.

In order to use goproxy, one should set his browser to use goproxy as an HTTP proxy. Here is how you do that in Chrome and in Firefox.

For example, the URL you should use as proxy when running ./bin/basic is localhost:8080, as this is the default binding for the basic proxy.

Mailing List

New features would be discussed on the mailing list before their development.

Latest Stable Release

Get the latest goproxy from gopkg.in/elazarl/goproxy.v1.

Why not Fiddler2?

Fiddler is an excellent software with similar intent. However, Fiddler is not as customable as goproxy intend to be. The main difference is, Fiddler is not intended to be used as a real proxy.

A possible use case that suits goproxy but not Fiddler, is, gathering statisitics on page load times for a certain website over a week. With goproxy you could ask all your users to set their proxy to a dedicated machine running a goproxy server. Fiddler is a GUI app not designed to be ran like a server for multiple users.

A taste of goproxy

To get a taste of goproxy, a basic HTTP/HTTPS transparent proxy

import (
    "github.com/elazarl/goproxy"
    "log"
    "net/http"
)

func main() {
    proxy := goproxy.NewProxyHttpServer()
    proxy.Verbose = true
    log.Fatal(proxy.ListenAndServe(":8080"))
}

This line will add X-GoProxy: yxorPoG-X header to all requests sent through the proxy

proxy.HandleRequestFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next {
    ctx.Req.Header.Set("X-GoProxy","yxorPoG-X")
    return goproxy.NEXT  // continue on with next handlers
    // or, return goproxy.FORWARD  // to short circuit other handlers, and continue on with forwarding
})

Here is a more complex/complete example:

proxy.HandleConnectFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next {
    if ctx.SNIHost() == "secure.example.com:443" {
        return goproxy.MITM
    }
    return goproxy.REJECT
})
proxy.HandleRequestFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next {
    if ctx.IsThroughMITM {
        ctx.Req.Header.Set("X-Snooped-On", "absolutely")
    }
    return goproxy.NEXT  // continue on with next handlers
    // or, return goproxy.FORWARD  // to short circuit other handlers, and continue on with forwarding
})

By setting Request Handlers, you can set a response directly and have it short-circuit the proxying to a remote server:

proxy.HandleRequestFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next {
    if ctx.URL.Path == "/super/bob" {
        //ctx.NewResponse(...)
        //ctx.NewHTMLResponse("<strong>welcome home</strong>")
        ctx.NewTextResponse("welcome home")
    }
    return goproxy.FORWARD
})

See additional examples in the examples directory.

What's New

  1. Major overhaul of API. Pretty much everything will break if you merely try this version.

  2. Ability to do optional SNI sniffing, and take action based on that information.

  3. Ability to FakeDestinationDNS() and SetDestinationHost().. to redirect requests.

  4. Ability to save network flows in .har format. See http://www.softwareishard.com/har/viewer/ and view with this tool: http://ericduran.github.io/chromeHAR/

  5. Ability to Hijack CONNECT requests. See the eavesdropper example

  6. Transparent proxy support for http/https including MITM certificate generation for TLS. See the transparent example.

License

I put the software temporarily under the Go-compatible BSD license, if this prevents someone from using the software, do let mee know and I'll consider changing it.

At any rate, user feedback is very important for me, so I'll be delighted to know if you're using this package.

Beta Software

I've received a positive feedback from a few people who use goproxy in production settings. I believe it is good enough for usage.

I'll try to keep reasonable backwards compatability. In case of a major API change, I'll change the import path.

Documentation

Overview

Taken from $GOROOT/src/pkg/net/http/chunked needed to write https responses to client.

Package goproxy provides a customizable HTTP proxy, supporting hijacking HTTPS connection.

The intent of the proxy, is to be usable with reasonable amount of traffic yet, customizable and programable.

The proxy itself is simply an `net/http` handler.

Typical usage is

proxy := goproxy.NewProxyHttpServer()
proxy.Verbose = true
proxy.HandleRequestFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next {
	if ctx.Host() == "example.com:80" {
		ctx.SetDestinationHost("127.0.0.1:8080")
		return goproxy.FORWARD
	}
	return goproxy.NEXT
})
proxy.ListenAndServe(":8080")

Adding a header to each request:

proxy.HandleRequestFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next {
	ctx.Req.Header.Set("X-GoProxy","1")
	return goproxy.NEXT
})

For printing the content type of all incoming responses

proxy.HandleResponseFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next {
	fmt.Println(ctx.Req.Host, "->", ctx.Req.Header.Get("Content-Type"))
	return goproxy.NEXT
})

Note the use of `ctx.Req` here. The `ctx` holds `Req` and `Resp`. `Resp` can be nil if not available.

To print the content type of all responses from a certain url, we'll add a "middleware" before:

golangOrgOnly := goproxy.UrlHasPrefix("golang.org/pkg")
logInYourFace := func(ctx *goproxy.ProxyCtx) goproxy.Next {
	fmt.Println(ctx.Req.Host, "->", ctx.Req.Header.Get("Content-Type"))
	return goproxy.NEXT
}
proxy.HandleResponseFunc(golangOrgOnly(logInYourFace))

To invalide responses based on headers for example, you can:

proxy.HandleResponseFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next {
	if ctx.Resp.Header.Get("X-GoProxy") == "" {
		ctx.Resp.Close()
		http.Error(ctx.ResponseWriter, "Denied.. didn't find an X-GoProxy header!", 403)
		return goproxy.DONE
	}
	return goproxy.NEXT
})

We close the body of the original repsonse, and return a new 403 response with a short message.

You can catch traffic going through the proxy selectively, and write it to a HAR formatted file with this code:

proxy.HandleRequestFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next {
	if ctx.Host() == "example.com:80" {
		ctx.LogToHARFile(true)
	}
	return goproxy.NEXT
})
proxy.NonProxyHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/har" {
		proxy.FlushHARToDisk("/tmp/file.har")
		w.WriteHeader(201)
		w.Write([]byte("hello world!\n"))
	}
})

You then "curl http://localhost:8888/har" to provoke a file flush to "/tmp/file.har".

Example use cases:

1. https://github.com/stoplightio/goproxy/tree/master/examples/goproxy-avgsize

To measure the average size of an Html served in your site. One can ask all the QA team to access the website by a proxy, and the proxy will measure the average size of all text/html responses from your host.

2. [not yet implemented]

All requests to your web servers should be directed through the proxy, when the proxy will detect html pieces sent as a response to AJAX request, it'll send a warning email.

3. https://github.com/stoplightio/goproxy/blob/master/examples/goproxy-httpdump/

Generate a real traffic to your website by real users using through proxy. Record the traffic, and try it again for more real load testing.

4. https://github.com/stoplightio/goproxy/tree/master/examples/goproxy-no-reddit-at-worktime

Will allow browsing to reddit.com between 8:00am and 17:00pm

5. https://github.com/stoplightio/goproxy/tree/master/examples/goproxy-jquery-version

Will warn if multiple versions of jquery are used in the same domain.

6. https://github.com/stoplightio/goproxy/blob/master/examples/goproxy-upside-down-ternet/

Modifies image files in an HTTP response via goproxy's image extension found in ext/.

Index

Constants

View Source
const (
	NEXT = Next(iota) // Continue to the next Handler
	MOCK
	DONE    // Implies that no further processing is required. The request has been fulfilled completely.
	FORWARD // Continue directly with forwarding, going through Response Handlers
	MITM    // Continue with Man-in-the-middle attempt, either through HTTP or HTTPS.
	REJECT  // Reject the CONNECT attempt outright
)

Variables

View Source
var AlwaysForward = HandlerFunc(func(ctx *ProxyCtx) Next {
	return FORWARD
})
View Source
var AlwaysMitm = HandlerFunc(func(ctx *ProxyCtx) Next {
	ctx.SNIHost()
	return MITM
})
View Source
var AlwaysReject = HandlerFunc(func(ctx *ProxyCtx) Next {
	return REJECT
})
View Source
var CA_CERT = []byte(`-----BEGIN CERTIFICATE-----
MIIC/TCCAeWgAwIBAgIRALVzNa8DPRRGV0QBro07S7UwDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNzAyMTYxNTA0MDVaFw0yNzAyMTQxNTA0
MDVaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCf5PWDdpWwMSSogQ0EcvR58pkU5tncQ9ektJ0GSrfLd/hR17M5+xKq
cFDlWGB7uKUU+6uM4UQnrbYzx97MUCnh5Ie58Hgb9jdx+A3eYCzneJWoBtJcsiMd
TFbjVEuqyFWVcy/dzfrmwEiyH2xHmMhJ/SnVpZa1MG9bjxJwuUECQMjbShePW5bK
XCMpIGyqHENRQg6wXRf1NykaSD+2yu4v+sljiCDy/VbmJDkoiyRtBsdxTncITKa3
LPbZnZtJS26SpYkDpNpAzt2bWkkrxh9isV2S4MNqrO7CjNNawEmkSs7yv+LhCvYN
i+9x3QTuJJ3QEoxIjJ2qv02tzlj5RidXAgMBAAGjTjBMMA4GA1UdDwEB/wQEAwIC
pDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MBQGA1UdEQQN
MAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAZq4a3eBSmC3PCD8Pte4h
zdgTNK22Zh1YCD+rVaDC8v9igJ69s+ggQl1VwzgIUd90mXAElBHmqjPffT5Ao1E5
ph+7Kdt4H04ugpLDZGfeOB6k5OMRbiEvgz5XRVPQVBcLTAvEit23ifVSbqkfMRh5
dO3dhRG0sxdKN+eFzxnXp4mGpcIniPYTsRE0Zee5ESMsw72S6iFFR9pokhUw9ESN
EQ+bJpd63nxMEkahFHBBrC/74obmg58pYbGyVlE1UuqN49WYgqL83Id+EQSwHzrn
hNqXKv3sGnFl4uUCRCc/PNRUdCkhPp5v9W6k5rMYwGxBb4QBrU12PpUWoqwV8dFi
8A==
-----END CERTIFICATE-----`)
View Source
var CA_KEY = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAn+T1g3aVsDEkqIENBHL0efKZFObZ3EPXpLSdBkq3y3f4Udez
OfsSqnBQ5Vhge7ilFPurjOFEJ622M8fezFAp4eSHufB4G/Y3cfgN3mAs53iVqAbS
XLIjHUxW41RLqshVlXMv3c365sBIsh9sR5jISf0p1aWWtTBvW48ScLlBAkDI20oX
j1uWylwjKSBsqhxDUUIOsF0X9TcpGkg/tsruL/rJY4gg8v1W5iQ5KIskbQbHcU53
CEymtyz22Z2bSUtukqWJA6TaQM7dm1pJK8YfYrFdkuDDaqzuwozTWsBJpErO8r/i
4Qr2DYvvcd0E7iSd0BKMSIydqr9Nrc5Y+UYnVwIDAQABAoIBAHkVzI832HfLX3Vz
9UWvQFCxVRgtEkLp5X5HgLppDvK48YYZERMRfbswvzJPURGgbPOM+wb++LwLovVn
oOOcuXrls5st7edO+AII1YfX0WmhOcQ7Fkc4Z7siOpKBHaRBff5lcpRIDn98khDC
Fx/JJbRSUcIHWi/wdAQkPtS6le57qqBl2wGRIbV3/6Hjq15X2UJCtzrGjY3IcYKp
lwL2C7boEEppQLXodVdXewfoM+6v76g/Vtx4qaLapCaVnv8GthtcejQhHIgZO5ZR
j1ANuaVWPDi0CoLWDCQAOlrDiQbTQtdgyV0uG+3JGxW2SW2uv15N9Fn1eELf8S29
CwmW6yECgYEAzqDwjRR+sOMdUKHCPHYHa+7V1t/dvmaEJaSsORo9gMLauqLbQGy5
2zTIHoIzIzrW6IjFtVkThKmof+6JdBbINKShLtkNsl3Pr9fuhRsE7qxTnWen4BmM
p4fx83xhQrEcSya+9Uj19spfKTxM/+sfhGhKavWjJ+0Fumqd8IMuvskCgYEAxhlg
UmSZeWSXJ9CGUpu+eZkZdoUQxGwzka9iuGE/qM1eFWd7idx4owexaHLOqf9rxACb
fuMbREOn+n8zsTynsvNLw6CPtDlV4QB08wcFX14hk+WGDujDWppOyiXKsytHzUmG
Q1KycHwa/qVNVtSy2hlRtJxYNwwDupRl73+6JR8CgYAqLprNAkkWzVaXtl4Tv7im
JRzMf+khzIXftW1fPucdWSoT/dkqnseWY4ETEVtlLsbes8VAz013wLbgXw76fwgi
DxXEnZT5O8OBT2CnFav9GXr8YEPaMP0Q2mTfYx3r4oI3KVLEej+UQR4KKgBCInrN
qgi/KyRCq1WHB+r0RaOOWQKBgETibBkafDe3H8yreRneqGRWNYF+Ee+LhH8jUpu0
zVMgXpfozQ+KR7TBJxKf4XdBpzKX13pO9JtPP2ketFXsNpBGg9D50x6jVVaRNxmP
FnIsJFbuWCh1DgFCaSVn8M1OvoAHEhX0+rGcpjJoPrVz7uFiLoQ0XYR+vAk0MyIN
8yeXAoGAEYDoNb8fcOnUOac9ziIqP2cZkl3jY9bom2Pm4xgsxrvdT29WTdKUXDnv
McrO0jsnBcEeA2jQjCZ5ZZ6zsKRvPtYHjHzcUCYhc1HI5QIK49ObuHGGzYIPhcIv
irIev81IwGZcLkKJ1U1P7sDpT07gXpdKMAfur6OgSd3oq25NH8E=
-----END RSA PRIVATE KEY-----`)
View Source
var MaxSerialNumber = big.NewInt(0).SetBytes(bytes.Repeat([]byte{255}, 20))

MaxSerialNumber is the upper boundary that is used to create unique serial numbers for the certificate. This can be any unsigned integer up to 20 bytes (2^(8*20)-1).

Functions

func CondRemoteAddrIs

func CondRemoteAddrIs(ctx *ProxyCtx, ip string) bool

func HostsToMap

func HostsToMap(hosts ...string) map[string]bool

func MatchIsLocalhost

func MatchIsLocalhost(req *http.Request) bool

func MatchRequestHostMap

func MatchRequestHostMap(req *http.Request, hosts map[string]bool) bool

func NewResponse

func NewResponse(r *http.Request, status int, contentType, body string) *http.Response

Will generate a valid http response to the given request the response will have the given contentType, and http status. Typical usage, refuse to process requests to local addresses:

 proxy.HandleRequest(IsLocalhost(HandlerFunc(func(ctx *ProxyCtx) Next {
	    ctx.NewResponse(http.StatusUnauthorized, "text/html", "<html><body>Can't use proxy for local addresses</body></html>")
	    return FORWARD
  })))

Types

type ChainedHandler

type ChainedHandler func(Handler) Handler

func RemoteAddrIs

func RemoteAddrIs(ip string) ChainedHandler

MatchRemoteAddr returns a ReqCondtion testing wether the source IP of the request is the given string, Was renamed from `SrcIpIs`.

func RemoteAddrIsNot

func RemoteAddrIsNot(ip string) ChainedHandler

func ReqHostMatches

func ReqHostMatches(regexps ...*regexp.Regexp) ChainedHandler

ReqHostMatches is a middleware that tests whether the host to which the request was directed to matches any of the given regular expressions.

func RequestHostContains

func RequestHostContains(hosts ...string) ChainedHandler

RequestHostContains is a middleware that tests whether the host to which the request is directed to contains one of the given strings.

func RequestHostIsIn

func RequestHostIsIn(hosts ...string) ChainedHandler

RequestHostIsIn is a middleware that tests whether the host to which the request is directed to equal to one of the given strings.

This matcher supersedes and combines DstHostIs and ReqHostIs.

func RequestHostIsNotIn

func RequestHostIsNotIn(hosts ...string) ChainedHandler

func RespContentTypeIs

func RespContentTypeIs(types ...string) ChainedHandler

RespContentTypeIs is a middleware to filter apply a handler only to those requests matching a given content-type.

imageHandler := HandlerFunc(func(ctx *ProxyCtx) Next {
    ... convert ctx.Resp.Body, reinject a new Body with a png, and change the Content-Type
    return FORWARD  // side-steps further modifications
    // or return NEXT  // to continue on with other Handlers
}

proxy.HandleRequest(RespContentTypeIs("image/jpeg", "image/gif")(imageHandler))

func UrlHasPrefix

func UrlHasPrefix(prefix string) ChainedHandler

UrlHasPrefix is a middleware matching when the destination URL the proxy client has requested has the given prefix, with or without the host.

For example UrlHasPrefix("host/x") will match requests of the form 'GET host/x', and will match requests to url 'http://host/x'

func UrlIsIn

func UrlIsIn(urls ...string) ChainedHandler

UrlIsIn is a middleware that tests if the URL matches `urls`, testing whether or not the request URL is one of the given strings with or without the host prefix.

UrlIsIn("google.com/","foo") will match these three cases: * 'GET /' with 'Host: google.com' * 'GET google.com/' * 'GET /foo' for any host

func UrlMatches

func UrlMatches(re *regexp.Regexp) ChainedHandler

UrlMatches returns a ReqCondition testing whether the destination URL of the request matches the given regexp, with or without prefix

type CounterEncryptorRand

type CounterEncryptorRand struct {
	// contains filtered or unexported fields
}

func NewCounterEncryptorRandFromKey

func NewCounterEncryptorRandFromKey(key interface{}, seed []byte) (r CounterEncryptorRand, err error)

func (*CounterEncryptorRand) Read

func (c *CounterEncryptorRand) Read(b []byte) (n int, err error)

func (*CounterEncryptorRand) Seed

func (c *CounterEncryptorRand) Seed(b []byte)

type GoproxyConfig

type GoproxyConfig struct {
	Root *x509.Certificate

	*tls.Config
	// contains filtered or unexported fields
}

Config is a set of configuration values that are used to build TLS configs capable of MITM.

var GoproxyCaConfig *GoproxyConfig

func LoadCAConfig

func LoadCAConfig(caCert, caKey []byte) (*GoproxyConfig, error)

Load a CAConfig bundle from by arrays. You can then load them into the proxy with `proxy.SetMITMCertConfig`

func NewConfig

func NewConfig(ca *x509.Certificate, privateKey interface{}) (*GoproxyConfig, error)

NewConfig creates a MITM config using the CA certificate and private key to generate on-the-fly certificates.

type Handler

type Handler interface {
	Handle(ctx *ProxyCtx) Next
}

func IsLocalhost

func IsLocalhost(chainedHandler Handler) Handler

IsLocalhost checks whether the destination host is explicitly local host (buggy, there can be IPv6 addresses it doesn't catch)

func IsNotLocalhost

func IsNotLocalhost(chainedHandler Handler) Handler

type HandlerFunc

type HandlerFunc func(ctx *ProxyCtx) Next

func (HandlerFunc) Handle

func (f HandlerFunc) Handle(ctx *ProxyCtx) Next

type Next

type Next int

Next indicates the return values possible for handlers.

In `request` handlers, `NEXT` means continue to the next handler. If none are left, it continues on with `FORWARD`. If you return `FORWARD`, then you skip all the other registered request handlers, and forward the request directly to the remote server, unless you've set a `ctx.Resp` before, in which case the response is sent back without touching any Response Handlers. If you return `REJECT`, the library will return a 502 error to the requester. In the `request` handlers, returning `MITM` will panic.

In Response handlers, `NEXT` means continue with the other registered handlers. If this was the last, the library will finish the forwarding of the current `ctx.Resp`. When `DONE` is returned, the library doesn't do anything else. It assumes you have properly written to `ctx.ResponseWriter` with a proper response (along with `ctx.Req`, this would resemble closely native `net/http` request handling). When `FORWARD` is returned, the lib jumps directly to the forwarding step, instead of going through the other response handlers. When `MITM` is returned, the lib will panic. When `REJECT` is returned, the lib will panic also. You can reject a request, but not a response.

In Connect handlers, `NEXT` means continue on with the next Connect handler. `FORWARD` means continue on with forwarding the raw TCP socket. `MITM` means jump in the middle and try to man-in-the-middle the connection. With the `MITM` option, all future requests to be detected from within the tunnel will trigger the Request handlers, in the order they were registered, just like a normal request arriving directly outside a tunnel. Those requests that are MITM will have the `ctx.IsThroughMITM` property set to `true`. Returning `REJECT` will reject the connection altogether. If you did sniff with `SNIHost()`, then the lib will forcefully close the connection, violating the protocol (you wanted to sniff, so it's your fault, right ? :). If you didn't sniff SNI, then a `502 Rejected` will be sent propertly to the client before closing the connection. `DONE` is not valid in that context, you need take a decision.

type ProxyCtx

type ProxyCtx struct {
	Method          string
	SourceIP        string
	IsSecure        bool // Whether we are handling an HTTPS request with the client
	IsThroughMITM   bool // Whether the current request is currently being MITM'd
	IsThroughTunnel bool // Whether the current request is going through a CONNECT tunnel, doing HTTP calls (non-secure)

	MITMCertConfig *GoproxyConfig

	// OriginalRequest holds a copy of the request before doing some HTTP tunnelling through CONNECT, or doing a man-in-the-middle attack.
	OriginalRequest *http.Request

	// Will contain the client request from the proxy
	Req            *http.Request
	ResponseWriter http.ResponseWriter

	// Connections, up (the requester) and downstream (the server we forward to)
	Conn net.Conn

	// Resp constains the remote sever's response (if available). This can be nil if the request wasn't sent yet, or if there was an error trying to fetch the response. In this case, refer to `ResponseError` for the latest error.
	Resp *http.Response

	// ResponseError contains the last error, if any, after running `ForwardRequest()` explicitly, or implicitly forwarding a request through other means (like returning `FORWARD` in some handlers).
	ResponseError error

	// RoundTripper is used to send a request to a remote server when
	// forwarding a Request.  If you set your own RoundTripper, then
	// `FakeDestinationDNS` and `LogToHARFile` will have no effect.
	RoundTripper RoundTripper

	// will contain the recent error that occured while trying to send receive or parse traffic
	Error error

	// UserObjects and UserData allow you to keep data between
	// Connect, Request and Response handlers.
	UserObjects map[string]interface{}
	UserData    map[string]string

	// Will connect a request to a response
	Session int64
	// contains filtered or unexported fields
}

ProxyCtx is the Proxy context, contains useful information about every request. It is passed to every user function. Also used as a logger.

func (*ProxyCtx) BufferResponse

func (ctx *ProxyCtx) BufferResponse() ([]byte, error)

BufferResponse reads the whole Resp.Body and returns a byte array. It is the caller,s responsibility to set a new Body with `SetResponseBody` afterwards. Otherwise, the Resp.Body will be in a closed state and that is not fun for other parts of your program. This replaces the need for goproxy's previous `HandleBytes` implementation.

func (*ProxyCtx) Charset

func (ctx *ProxyCtx) Charset() string

Will try to infer the character set of the request from the headers. Returns the empty string if we don't know which character set it used. Currently it will look for charset=<charset> in the Content-Type header of the request.

func (*ProxyCtx) DispatchDoneHandlers

func (ctx *ProxyCtx) DispatchDoneHandlers() error

func (*ProxyCtx) DispatchResponseHandlers

func (ctx *ProxyCtx) DispatchResponseHandlers() error

func (*ProxyCtx) FakeDestinationDNS

func (ctx *ProxyCtx) FakeDestinationDNS(host string)

FakeDestinationDNS will force a connection to the specified host/ip instead of the normal DNS resolution of the `SetDestinationHost()`. This will assume the destination server will answer as if it was ctx.Host().

If you specify a port, it will also serve in the redirection, otherwise the port from `ctx.Host()` will be used.

func (*ProxyCtx) FlushHARToDisk

func (ctx *ProxyCtx) FlushHARToDisk(filename string)

func (*ProxyCtx) ForwardConnect

func (ctx *ProxyCtx) ForwardConnect() error

func (*ProxyCtx) ForwardRequest

func (ctx *ProxyCtx) ForwardRequest(host string) error

func (*ProxyCtx) ForwardResponse

func (ctx *ProxyCtx) ForwardResponse(resp *http.Response) error

func (*ProxyCtx) HijackConnect

func (ctx *ProxyCtx) HijackConnect() net.Conn

func (*ProxyCtx) Host

func (ctx *ProxyCtx) Host() string

Host() returns the "host:port" to which your request will be forwarded. For a CONNECT request, it is preloaded with the original request's "host:port". For other methods, it is preloaded with the request's host and an added port based on the scheme (unless the port was specified).

If you sniff the SNI host with `ctx.SNIHost()`, it will alter the value returned by `Host()` to reflect what was sniffed. You need that to properly MITM secure CONNECT calls, otherwise the remote end will always fail to recognize the certificates this lib signs on-the-fly.

You can alter this value with `SetDestinationHost()`.

func (*ProxyCtx) LogToHARFile

func (ctx *ProxyCtx) LogToHARFile(captureContent bool) Next

LogToHARFile collects all the content from the Request/Response roundtrip and stores it in memory until you call `FlushHARToDisk(filename)`.. at which point it will all be flushed to disk in HAR file format.

LogToHARFile alwasy returns `NEXT`.

func (*ProxyCtx) Logf

func (ctx *ProxyCtx) Logf(msg string, argv ...interface{})

Logf prints a message to the proxy's log. Should be used in a ProxyHttpServer's filter This message will be printed only if the Verbose field of the ProxyHttpServer is set to true

proxy.OnRequest().DoFunc(func(r *http.Request,ctx *goproxy.ProxyCtx) (*http.Request, *http.Response){
	nr := atomic.AddInt32(&counter,1)
	ctx.Printf("So far %d requests",nr)
	return r, nil
})

func (*ProxyCtx) ManInTheMiddle

func (ctx *ProxyCtx) ManInTheMiddle() error

ManInTheMiddle triggers either a full-fledged MITM when done through HTTPS, otherwise, simply tunnels future HTTP requests through the CONNECT stream, dispatching calls to the Request Handlers

func (*ProxyCtx) ManInTheMiddleHTTPS

func (ctx *ProxyCtx) ManInTheMiddleHTTPS() error

ManIntheMiddleHTTPS assumes we're dealing with an TLS-wrapped CONNECT tunnel. It will perform a full-blown man-in-the-middle attack, and forward any future requests received from inside the TSL tunnel to the Request Handlers.

Requests in there will be marked `IsSecure = true` (although, you and me know it's not *totally* secure, huh ?). They will also have the `ctx.IsThroughMITM` flag set to true.

The `ctx.OriginalRequest` will also hold the original CONNECT request from which the tunnel originated.

func (*ProxyCtx) NewHTMLResponse

func (ctx *ProxyCtx) NewHTMLResponse(body string)

func (*ProxyCtx) NewResponse

func (ctx *ProxyCtx) NewResponse(status int, contentType, body string)

func (*ProxyCtx) NewTextResponse

func (ctx *ProxyCtx) NewTextResponse(body string)

func (*ProxyCtx) RejectConnect

func (ctx *ProxyCtx) RejectConnect()

func (*ProxyCtx) RoundTrip

func (ctx *ProxyCtx) RoundTrip(req *http.Request) (*http.Response, error)

func (*ProxyCtx) SNIHost

func (ctx *ProxyCtx) SNIHost() string

SNIHost will try preempt the TLS handshake and try to sniff the Server Name Indication. It returns `Host()` for non CONNECT requests, so it is always safe to call. If it sniffed successfully, but didn't find anything, it is possible to return an empty string.

func (*ProxyCtx) SetConnectScheme

func (ctx *ProxyCtx) SetConnectScheme(scheme string)

SetConnectScheme determines how to interprete the TCP conversation following a CONNECT request. `scheme` can be "http" or "https". By default, it uses a simple heuristic: "http" if CONNECT asked for port 80, otherwise it always assumes "https" when trying to man-in-the-middle. Call this before returning `MITM` from Connect Handlers.

func (*ProxyCtx) SetDestinationHost

func (ctx *ProxyCtx) SetDestinationHost(host string)

SetDestinationHost sets the "host:port" to which you want to FORWARD or MITM a CONNECT request. Otherwise defaults to what was in the `CONNECT` request. If you call `SNIHost()` to sniff SNI, then this will override the destination host automatically.

If you want to alter the destination host of a *Request* that goes through a tunnel you can eavesdrop, modify `ctx.Req.URL.Host`, the RoundTrip will go to that address, even though the `ctx.Req.Host` is used as the `Host:` header. You can identify those requests with `ctx.IsThroughMITM` or `ctx.IsThroughTunnel`.

func (*ProxyCtx) SetResponseBody

func (ctx *ProxyCtx) SetResponseBody(content []byte)

SetResponseBody overwrites the Resp.Body with the given content. It is the caller's responsibility to ensure the previous Body was read and/or closed properly. Use `BufferResponse()` for that. This call will fail if ctx.Resp is nil.

func (*ProxyCtx) TunnelHTTP

func (ctx *ProxyCtx) TunnelHTTP() error

TunnelHTTP assumes the current connection is a plain HTTP tunnel, with no security. It then dispatches all future requests in there through the registered Request Handlers.

Requests flowing through this tunnel will be marked `ctx.IsThroughTunnel == true`.

You can also find the original CONNECT request in `ctx.OriginalRequest`.

func (*ProxyCtx) Warnf

func (ctx *ProxyCtx) Warnf(msg string, argv ...interface{})

Warnf prints a message to the proxy's log. Should be used in a ProxyHttpServer's filter This message will always be printed.

proxy.OnRequest().DoFunc(func(r *http.Request,ctx *goproxy.ProxyCtx) (*http.Request, *http.Response){
	f,err := os.OpenFile(cachedContent)
	if err != nil {
		ctx.Warnf("error open file %v: %v",cachedContent,err)
		return r, nil
	}
	return r, nil
})

type ProxyHttpServer

type ProxyHttpServer struct {

	// setting Verbose to true will log information on each request sent to the proxy
	Verbose bool
	// SniffSNI enables sniffing Server Name Indicator when doing CONNECT calls.  It will thus answer to CONNECT calls with a "200 OK" even if the remote server might not answer.  The result would be the shutdown of the connection instead of an appropriate HTTP error code if the remote node doesn't answer.
	SniffSNI bool
	Logger   *log.Logger

	// NonProxyHandler will be used to handle direct connections to the proxy. You can assign an `http.ServeMux` or some other routing libs here.  The default will return a 500 error saying this is a proxy and has nothing to serve by itself.
	NonProxyHandler http.Handler

	// Custom transport to be used
	Transport *http.Transport

	// Setting MITMCertConfig allows you to override the default CA cert/key used to sign MITM'd requests.
	MITMCertConfig *GoproxyConfig

	// ConnectDial will be used to create TCP connections for CONNECT requests
	// if nil, .Transport.Dial will be used
	ConnectDial func(network string, addr string) (net.Conn, error)
	// contains filtered or unexported fields
}

The basic proxy type. Implements http.Handler.

func NewProxyHttpServer

func NewProxyHttpServer() *ProxyHttpServer

New proxy server, logs to StdErr by default

func (*ProxyHttpServer) FlushHARToDisk

func (proxy *ProxyHttpServer) FlushHARToDisk(filename string)

func (*ProxyHttpServer) HandleConnect

func (proxy *ProxyHttpServer) HandleConnect(f Handler)

func (*ProxyHttpServer) HandleConnectFunc

func (proxy *ProxyHttpServer) HandleConnectFunc(f func(ctx *ProxyCtx) Next)

HandleConnectFunc and HandleConnect mimic the `net/http` handlers, and register handlers for CONNECT proxy calls.

See `Next` values for the return value meaning

func (*ProxyHttpServer) HandleDone

func (proxy *ProxyHttpServer) HandleDone(f Handler)

func (*ProxyHttpServer) HandleDoneFunc

func (proxy *ProxyHttpServer) HandleDoneFunc(f func(ctx *ProxyCtx) Next)

HandleDoneFunc and HandleDone are called at the end of every request. Use them to cleanup.

See `Next` values for the return value meaning

func (*ProxyHttpServer) HandleRequest

func (proxy *ProxyHttpServer) HandleRequest(f Handler)

func (*ProxyHttpServer) HandleRequestFunc

func (proxy *ProxyHttpServer) HandleRequestFunc(f func(ctx *ProxyCtx) Next)

HandleRequestFunc and HandleRequest put hooks to handle certain requests. Note that MITM'd and HTTP requests that go through a CONNECT'd connection also go through those Request Handlers.

See `Next` values for the return value meaning

func (*ProxyHttpServer) HandleResponse

func (proxy *ProxyHttpServer) HandleResponse(f Handler)

func (*ProxyHttpServer) HandleResponseFunc

func (proxy *ProxyHttpServer) HandleResponseFunc(f func(ctx *ProxyCtx) Next)

HandleResponseFunc and HandleResponse put hooks to handle certain requests. Note that MITM'd and HTTP requests that go through a CONNECT'd connection also go through those Response Handlers.

See `Next` values for the return value meaning

func (*ProxyHttpServer) ListenAndServe

func (proxy *ProxyHttpServer) ListenAndServe(addr string) error

ListenAndServe launches all the servers required and listens. Use this method if you want to start listeners for transparent proxying.

func (*ProxyHttpServer) Logf

func (proxy *ProxyHttpServer) Logf(msg string, v ...interface{})

func (*ProxyHttpServer) NewConnectDialToProxy

func (proxy *ProxyHttpServer) NewConnectDialToProxy(https_proxy string) func(network, addr string) (net.Conn, error)

func (*ProxyHttpServer) ServeHTTP

func (proxy *ProxyHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request)

Standard net/http function. Shouldn't be used directly, http.Serve will use it.

func (*ProxyHttpServer) SetMITMCertConfig

func (proxy *ProxyHttpServer) SetMITMCertConfig(config *GoproxyConfig)

SetMITMCertConfig sets the CA Config to be used to sign man-in-the-middle'd certificates. You can load some []byte with `LoadCAConfig()`. This bundle gets passed into the `ProxyCtx` and may be overridden in the [TODO: FIXME] `HandleConnect()` callback, before doing SNI sniffing.

type RoundTripper

type RoundTripper interface {
	RoundTrip(req *http.Request, ctx *ProxyCtx) (*http.Response, error)
}

type RoundTripperFunc

type RoundTripperFunc func(req *http.Request, ctx *ProxyCtx) (*http.Response, error)

func (RoundTripperFunc) RoundTrip

func (f RoundTripperFunc) RoundTrip(req *http.Request, ctx *ProxyCtx) (*http.Response, error)

Directories

Path Synopsis
examples
goproxy-yui-minify
This example would minify standalone Javascript files (identified by their content type) using the command line utility YUI compressor http://yui.github.io/yuicompressor/ Example usage: ./yui -java /usr/local/bin/java -yuicompressor ~/Downloads/yuicompressor-2.4.8.jar $ curl -vx localhost:8080 http://golang.org/lib/godoc/godocs.js (function(){function g(){var u=$("#search");if(u.length===0){return}function t(){if(....
This example would minify standalone Javascript files (identified by their content type) using the command line utility YUI compressor http://yui.github.io/yuicompressor/ Example usage: ./yui -java /usr/local/bin/java -yuicompressor ~/Downloads/yuicompressor-2.4.8.jar $ curl -vx localhost:8080 http://golang.org/lib/godoc/godocs.js (function(){function g(){var u=$("#search");if(u.length===0){return}function t(){if(....
ext
html
extension to goproxy that will allow you to easily filter web browser related content.
extension to goproxy that will allow you to easily filter web browser related content.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL