goproxy

package module
v0.0.0-...-63c9735 Latest Latest
Warning

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

Go to latest
Published: Sep 19, 2023 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/abourget/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/abourget/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/abourget/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/abourget/goproxy/tree/master/examples/goproxy-jquery-version

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

6. https://github.com/abourget/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-----
MIID0TCCArmgAwIBAgIJAImi7ScXIjQkMA0GCSqGSIb3DQEBCwUAMH8xCzAJBgNV
BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjETMBEGA1UE
CgwKQmxhY2tIb3N0czELMAkGA1UECwwCSVQxDzANBgNVBAMMBkdob3N0czEbMBkG
CSqGSIb3DQEJARYMbm9uQG5vbmUuY29tMB4XDTIzMDkxODIxMzg0MVoXDTI2MDMx
ODIxMzg0MVowfzELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UE
BwwGTG9uZG9uMRMwEQYDVQQKDApCbGFja0hvc3RzMQswCQYDVQQLDAJJVDEPMA0G
A1UEAwwGR2hvc3RzMRswGQYJKoZIhvcNAQkBFgxub25Abm9uZS5jb20wggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHSFVk/qR6HoTezPRd9UzidXeGOBBU
LOj7z+Ki3zU1DGZVG2mYKh8ZpxGbJ4NPp/LjPWrQCgxTgm6vbhURIs+nluzFaKYT
Xkw0UHLL/hKbo6O0dO2/j4q4xeBu4LnNz28UsopH3H73F+6DZOlrDbvVr88r+QkS
ydx9I4tyyOOyXfqc06AfG8B3YjGLGuB1XVQOTrnzlcCKDRhXfm/a+JIIrgku/seW
zYz6KNEZJ8fJ6mbJrwuV36AEzdF+9zNlwYfRFjXBnfvPFbkO8S2h6eiyPuG3Bvcl
9rRZALLCIJd9rIdnZ5sn2ptVnpYa7EvU0fGgnyCHfrT3HDTPZFzDnxCBAgMBAAGj
UDBOMB0GA1UdDgQWBBS6KRqJpcOxJvOGiFVxngeyelwaCDAfBgNVHSMEGDAWgBS6
KRqJpcOxJvOGiFVxngeyelwaCDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
A4IBAQC2n2dxFMsSIS4cv7i+XHLAqoZYdqoLbdRf60Hsksh5hMqqnqlQeIUCkfIe
do8thmDRMLjvf4CwTa17JL8h/wS9krl5E94rP7HX5/5AdQrsiY6JYrhf4UG3eAfA
62Y8C0/D5KCE6Rb20JBcmy7ldXAeoBxusBihySSESimdUKoDvL3Y6VAtert/iClc
xca45gSb6JDinRhD5bnbMQ2N8mSvz9ANL1GGXDH/FPJwi+pOS/KygpSV3mL+fp+I
qxkmbzx1N/FGW0gjhGUcHFK+S8KspWVmTLuKvIAxIuSMsDbFqjME6VSWdv0TaklW
tuUasOnwOrPG0YSw1UoHk+8+2kjg
-----END CERTIFICATE-----`)
View Source
var CA_KEY = []byte(`-----BEGIN RSA PRIVATE KEY-----

-----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).

View Source
var OrganizationName = "GoProxy untrusted MITM proxy Inc"

OrganizationName is the name your CA cert will be signed with. It will show in your different UIs. Change it globally here to show meaningful things to your users.

Functions

func CondRemoteAddrIs

func CondRemoteAddrIs(ctx *ProxyCtx, ip string) bool

func HostsToMap

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

func LoadDefaultConfig

func LoadDefaultConfig() error

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:
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:
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