in main.go [88:166]
func forwardRequest(req *http.Request, reqSourceIP string, reqDestionationPort string, body []byte) {
// if percentage flag is not 100, then a percentage of requests is skipped
if *fwdPerc != 100 {
var uintForSeed uint64
if *fwdBy == "" {
// if percentage-by is empty, then forward only a certain percentage of requests
var b [8]byte
_, err := crypto_rand.Read(b[:])
if err != nil {
log.Println("Error generating crypto random unit for seed", ":", err)
return
}
// uintForSeed is random
uintForSeed = binary.LittleEndian.Uint64(b[:])
} else {
// if percentage-by is not empty, then forward only requests from a certain percentage of headers/remoteaddresses
strForSeed := ""
if *fwdBy == "header" {
strForSeed = req.Header.Get(*fwdHeader)
} else {
strForSeed = reqSourceIP
}
crc64Table := crc64.MakeTable(0xC96C5795D7870F42)
// uintForSeed is derived from strForSeed
uintForSeed = crc64.Checksum([]byte(strForSeed), crc64Table)
}
// generate a consistent random number from the variable uintForSeed
math_rand.Seed(int64(uintForSeed))
randomPercent := math_rand.Float64() * 100
// skip a percentage of requests
if randomPercent > *fwdPerc {
return
}
}
// create a new url from the raw RequestURI sent by the client
url := fmt.Sprintf("%s%s", string(*fwdDestination), req.RequestURI)
// create a new HTTP request
forwardReq, err := http.NewRequest(req.Method, url, bytes.NewReader(body))
if err != nil {
return
}
// add headers to the new HTTP request
for header, values := range req.Header {
for _, value := range values {
forwardReq.Header.Add(header, value)
}
}
// Append to X-Forwarded-For the IP of the client or the IP of the latest proxy (if any proxies are in between)
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For
forwardReq.Header.Add("X-Forwarded-For", reqSourceIP)
// The three following headers should contain 1 value only, i.e. the outermost port, protocol, and host
// https://tools.ietf.org/html/rfc7239#section-5.4
if forwardReq.Header.Get("X-Forwarded-Port") == "" {
forwardReq.Header.Set("X-Forwarded-Port", reqDestionationPort)
}
if forwardReq.Header.Get("X-Forwarded-Proto") == "" {
forwardReq.Header.Set("X-Forwarded-Proto", "http")
}
if forwardReq.Header.Get("X-Forwarded-Host") == "" {
forwardReq.Header.Set("X-Forwarded-Host", req.Host)
}
// Execute the new HTTP request
httpClient := &http.Client{}
resp, rErr := httpClient.Do(forwardReq)
if rErr != nil {
// log.Println("Forward request error", ":", err)
return
}
defer resp.Body.Close()
}