-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HTTP / TCP Test Harness for JSON RPC #52
Draft
praetoriansentry
wants to merge
9
commits into
main
Choose a base branch
from
jhilliard/DVT-581-test-harness-for-reliability-tests
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
c2df624
feat: adding small POC for 4XX and 5XX errors
praetoriansentry 4640db5
feat: adding closed connection feature
praetoriansentry 5a6a418
feat: hanging connection
praetoriansentry cb19d47
feat: adding slow random
praetoriansentry 14c3990
feat: slow http mode
praetoriansentry 816ddf1
feat: adding huge http
praetoriansentry d63ae6d
refactor: adding a content type header and switching to http level
praetoriansentry 5bc0c10
feat: adding additional weird test and fixing bug with huge handler
praetoriansentry 2354d7d
feat: adding a script for l3 and l4 fun
praetoriansentry File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package testharness | ||
|
||
// junkJSONRPC is a static list of various test strings some of which are valid json but invalid json rpc. Some are just complete trash | ||
var junkJSONRPC = []string{ | ||
// These should be acceptable | ||
`{"jsonrpc": "2.0", "result": null, "id": 1}`, // null result should be fine | ||
`{"jsonrpc": "2.0", "result": 123, "id": 1}`, // number should be fine | ||
`{"jsonrpc": "2.0", "result": "123", "id": 1}`, // string should be fine | ||
`{"jsonrpc": "2.0", "result": [1, 2 ,3], "id": 1}`, // array should be fine | ||
`{"jsonrpc": "2.0", "result": {}, "id": 1}`, // empty object should be okay | ||
`{"jsonrpc": "2.0", "result": {"1": true, "2": true, "3": true}, "id": 1}`, // object should be okay | ||
`{"jsonrpc": "2.0", "result": 123, "id": "abc123"}`, // string id should be okay | ||
`[{"jsonrpc": "2.0", "result": 123, "id": 1},{"jsonrpc": "2.0", "result": 456, "id": 2}]`, // batch response | ||
`{"jsonrpc": "2.0", "error": {"code": -32700, "message": "test err"}, "id": null}`, // error response should be fine | ||
|
||
// these are dubious | ||
`{"jsonrpc": "2.0", "id": 1}`, // completely missing result | ||
`{"jsonrpc": "2", "result": 123, "id": 1}`, // 2 instead of 2.0 | ||
`{"jsonrpc": "2.0", "result": 123, "id": null}`, // null id | ||
`{"jsonrpc": "2.0", "result": 123, "id": 1}` + string([]byte{0}), // trailing null byte | ||
`{"jsonrpc": "2.0", "result": 123, "id": 1}` + "\r\n" + `{"jsonrpc": "2.0", "result": 123, "id": 1}`, // \r\n seperator | ||
`{"jsonrpc": "2.0", "result": 123, "id": 1}` + "\r" + `{"jsonrpc": "2.0", "result": 123, "id": 1}`, // \r seperator | ||
`{"jsonrpc": "2.0", "result": 123, "id": 1}` + "\n" + `{"jsonrpc": "2.0", "result": 123, "id": 1}`, // \n seperator | ||
`{"jsonrpc": "2.0", "result": 123}`, // missing id all together | ||
`{"result": 123, "id": 1}`, // missing json rpc all together.. This would be jsonrpc 1.0 | ||
`[{"jsonrpc": "2.0", "result": 123, "id": 1},{"jsonrpc": "2.0", "result": 123, "id": 1}]`, // batch response with two responses fro the same id | ||
`{"jsonrpc": "2.0", "error": {"code": -32700, "message": "test err"}, "id": 1}`, // error id must be null | ||
`{"jsonrpc": "2.0", "error": {"code": "foo", "message": "test err"}, "id": null}`, | ||
`{"jsonrpc": "2.0", "error": {"code": 2.718282828, "message": "test err"}, "id": null}`, // non-integer code | ||
`{"jsonrpc": "2.0", "error": {}, "id": null}`, // empty object for error | ||
`{"jsonrpc": "2.0", "error": null, "id": null}`, // numm error | ||
`{"jsonrpc": "2.0", "error": {"message": "test err"}, "id": null}`, // Missing code | ||
`{"jsonrpc": "2.0", "error": {"code": -32700}, "id": null}`, // missing message | ||
`{"jsonrpc": "2.0", "error": true, "id": null}`, // error is wrong type | ||
|
||
// these should break something | ||
`{"jsonrpc": "2.0", "result": , "id": 1}`, // missing result ... broken json | ||
`{"jsonrpc": "2.0", "result": "` + string([]byte{0}) + `", "id": 1}`, // null byte in result | ||
`{"jsonrpc": "2.0", "result": nil, "id": 1}`, // nil instead of null | ||
`{"jsonrpc": "2.0", "result": 123, "result": 456, "id": 1}`, // result specified twice? might work | ||
``, // valid json but probably will break | ||
`null`, // valid but should break | ||
`0`, // valid but should break rp | ||
`0x00`, // invalid I think | ||
`<xml />`, // wrong type | ||
`hi`, // invalid json | ||
`"hi"`, // valid json but should break | ||
string([]byte{0, 0, 0}), // null bytes should break | ||
} | ||
|
||
var junkContentTypeHeader = []string{ | ||
"application/javascript", | ||
"application/octet-stream", | ||
"application/xhtml+xml", | ||
"application/json", | ||
"application/xml", | ||
"application/x-www-form-urlencoded", | ||
"audio/x-wav", | ||
"image/gif", | ||
"image/png", | ||
"multipart/mixed", | ||
"multipart/form-data", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
#!/bin/bash | ||
|
||
# https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html#TRAVERSINGOFTABLES | ||
# https://inai.de/projects/xtables-addons/ | ||
# https://tldp.org/HOWTO/Traffic-Control-HOWTO/ | ||
|
||
# apt install linux-headers-$(uname -r) | ||
# apt install xtables-addons-dkms xtables-addons-common | ||
|
||
# geth --dev --dev.period 2 --ws --ws.addr 0.0.0.0 --ws.port 8546 --http --http.addr 0.0.0.0 --http.port 8545 --http.api admin,debug,web3,eth,txpool,personal,miner,net --verbosity 5 --rpc.gascap 50000000 --rpc.txfeecap 0 --miner.gaslimit 10 --miner.gasprice 1 --gpo.blocks 1 --gpo.percentile 1 --gpo.maxprice 10 --gpo.ignoreprice 2 --dev.gaslimit 50000000 | ||
# polycli testharness --listen-ip 0.0.0.0 | ||
|
||
|
||
readonly http_port=8545 | ||
readonly ws_port=8546 | ||
readonly harness_port=11235 | ||
|
||
readonly interface=enp1s0 | ||
|
||
|
||
cleanup () { | ||
tc qdisc del dev $interface root | ||
|
||
iptables -P INPUT ACCEPT | ||
iptables -P OUTPUT ACCEPT | ||
iptables -P FORWARD ACCEPT | ||
|
||
iptables -t filter -t raw -F | ||
iptables -t raw -F | ||
iptables -t nat -F | ||
iptables -t mangle -F | ||
} | ||
|
||
main () { | ||
# Allow port 22/ssh access | ||
iptables -I INPUT -p tcp --dport 22 -j ACCEPT | ||
|
||
# Setup root qdisc | ||
tc qdisc add dev $interface root handle 1: htb | ||
|
||
# Set default chain policies | ||
iptables -P INPUT DROP | ||
iptables -P FORWARD DROP | ||
iptables -P OUTPUT ACCEPT | ||
|
||
# Accept on localhost | ||
iptables -A INPUT -i lo -j ACCEPT | ||
iptables -A OUTPUT -o lo -j ACCEPT | ||
|
||
# Allow established sessions to receive traffic | ||
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT | ||
|
||
# Allow ICMP | ||
iptables -A INPUT -p icmp -j ACCEPT | ||
|
||
# Allow HTTP | ||
iptables -I INPUT -p tcp --dport $http_port -j ACCEPT | ||
iptables -I INPUT -p tcp --dport $ws_port -j ACCEPT | ||
iptables -I INPUT -p tcp --dport $harness_port -j ACCEPT | ||
|
||
# Allow 8000 | ||
iptables -t nat -A PREROUTING -p TCP --dport 8000 -j REDIRECT --to-port $http_port | ||
|
||
# DROP 8001 | ||
iptables -t filter -A INPUT -p TCP --dport 8001 -j DROP | ||
|
||
# REJECT 8002 | ||
iptables -t filter -A INPUT -p TCP --dport 8002 -j REJECT | ||
|
||
# TARPIT 8003 | ||
iptables -t filter -A INPUT -p TCP --dport 8003 -j TARPIT | ||
|
||
# DELUDE 8004 | ||
iptables -t filter -A INPUT -p TCP --dport 8004 -j DELUDE | ||
|
||
|
||
|
||
# Allow 8101 and Drop 10% of the packets in the way in | ||
iptables -t nat -A PREROUTING -p TCP --dport 8101 -j REDIRECT --to-port $http_port | ||
iptables -t raw -I PREROUTING -p TCP --dport 8101 -m statistic --mode random --probability 0.1 -j DROP | ||
|
||
# Allow 8102 and Drop 10% of the packets on the way out | ||
iptables -t mangle -A PREROUTING -p TCP --dport 8102 -j CONNMARK --set-mark 8102 | ||
iptables -t nat -A PREROUTING -p TCP --dport 8102 -j REDIRECT --to-port $http_port | ||
iptables -t mangle -A POSTROUTING -p TCP -m connmark --mark 8102 -m statistic --mode random --probability 0.1 -j DROP | ||
|
||
# Allow 8103 and add a 1 second delay | ||
iptables -t mangle -A PREROUTING -p TCP --dport 8103 -j CONNMARK --set-mark 8103 | ||
iptables -t nat -A PREROUTING -p TCP --dport 8103 -j REDIRECT --to-port $http_port | ||
iptables -t mangle -A POSTROUTING -p tcp -m connmark --mark 8103 -j CLASSIFY --set-class 1:3 | ||
tc class add dev $interface parent 1: classid 1:3 htb rate 1000mbps | ||
tc qdisc add dev $interface parent 1:3 handle 3: netem delay 1000ms | ||
# tc filter add dev $interface parent 1:0 protocol ip u32 match ip sport 8083 FFFF flowid 1:2 | ||
|
||
# Allow 8104 and add a packet limit of 2 | ||
iptables -t mangle -A PREROUTING -p TCP --dport 8104 -j CONNMARK --set-mark 8104 | ||
iptables -t nat -A PREROUTING -p TCP --dport 8104 -j REDIRECT --to-port $http_port | ||
iptables -t mangle -A POSTROUTING -p tcp -m connmark --mark 8104 -j CLASSIFY --set-class 1:4 | ||
tc class add dev $interface parent 1: classid 1:4 htb rate 1000mbps | ||
tc qdisc add dev $interface parent 1:4 handle 4: netem limit 2 | ||
|
||
# Allow 8105 and lose a random 20% of packets | ||
iptables -t mangle -A PREROUTING -p TCP --dport 8105 -j CONNMARK --set-mark 8105 | ||
iptables -t nat -A PREROUTING -p TCP --dport 8105 -j REDIRECT --to-port $http_port | ||
iptables -t mangle -A POSTROUTING -p tcp -m connmark --mark 8105 -j CLASSIFY --set-class 1:5 | ||
tc class add dev $interface parent 1: classid 1:5 htb rate 1000mbps | ||
tc qdisc add dev $interface parent 1:5 handle 5: netem loss random 20% | ||
|
||
# Allow 8106 and corrupt a random 20% of packets | ||
iptables -t mangle -A PREROUTING -p TCP --dport 8106 -j CONNMARK --set-mark 8106 | ||
iptables -t nat -A PREROUTING -p TCP --dport 8106 -j REDIRECT --to-port $http_port | ||
iptables -t mangle -A POSTROUTING -p tcp -m connmark --mark 8106 -j CLASSIFY --set-class 1:6 | ||
tc class add dev $interface parent 1: classid 1:6 htb rate 1000mbps | ||
tc qdisc add dev $interface parent 1:6 handle 6: netem corrupt 20% | ||
|
||
# Allow 8107 and duplicate a random 20% of packets | ||
iptables -t mangle -A PREROUTING -p TCP --dport 8107 -j CONNMARK --set-mark 8107 | ||
iptables -t nat -A PREROUTING -p TCP --dport 8107 -j REDIRECT --to-port $http_port | ||
iptables -t mangle -A POSTROUTING -p tcp -m connmark --mark 8107 -j CLASSIFY --set-class 1:7 | ||
tc class add dev $interface parent 1: classid 1:7 htb rate 1000mbps | ||
tc qdisc add dev $interface parent 1:7 handle 7: netem duplicate 20% | ||
|
||
# Allow 8108 and reorder a random 50% of packets | ||
iptables -t mangle -A PREROUTING -p TCP --dport 8108 -j CONNMARK --set-mark 8108 | ||
iptables -t nat -A PREROUTING -p TCP --dport 8108 -j REDIRECT --to-port $http_port | ||
iptables -t mangle -A POSTROUTING -p tcp -m connmark --mark 8108 -j CLASSIFY --set-class 1:8 | ||
tc class add dev $interface parent 1: classid 1:8 htb rate 1000mbps | ||
tc qdisc add dev $interface parent 1:8 handle 8: netem duplicate 50% | ||
|
||
# Allow 8109 and use a very slow rate limit | ||
iptables -t mangle -A PREROUTING -p TCP --dport 8109 -j CONNMARK --set-mark 8109 | ||
iptables -t nat -A PREROUTING -p TCP --dport 8109 -j REDIRECT --to-port $http_port | ||
iptables -t mangle -A POSTROUTING -p tcp -m connmark --mark 8109 -j CLASSIFY --set-class 1:9 | ||
tc class add dev $interface parent 1: classid 1:9 htb rate 1000mbps | ||
tc qdisc add dev $interface parent 1:9 handle 9: netem rate 56kbit | ||
|
||
|
||
} | ||
|
||
cleanup; | ||
main; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package testharness | ||
|
||
import ( | ||
"fmt" | ||
"github.com/rs/zerolog" | ||
"github.com/rs/zerolog/log" | ||
"github.com/spf13/cobra" | ||
"math/rand" | ||
"net" | ||
"net/http" | ||
"os" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
var ( | ||
harnessPort *uint16 | ||
listenAddr *string | ||
) | ||
|
||
const ( | ||
packetSize = 2<<15 - 1 | ||
HarnessIdentifier = "Test Harness" | ||
) | ||
|
||
type ( | ||
Handler500 struct{} | ||
Handler400 struct{} | ||
HandlerHuge struct{} | ||
HandlerJunk struct{} | ||
) | ||
|
||
var TestHarnessCmd = &cobra.Command{ | ||
Use: "testharness --mode [mode] --port [portnumber]", | ||
Short: "Run a simple test harness on the given port", | ||
Long: ``, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
log.Info().Uint16("port", *harnessPort).Str("ip", *listenAddr).Msg("Starting server") | ||
return startHarness() | ||
}, | ||
PreRunE: func(cmd *cobra.Command, args []string) error { | ||
parsedIp := net.ParseIP(*listenAddr) | ||
if parsedIp == nil { | ||
return fmt.Errorf("the ip %s could not be parsed", *listenAddr) | ||
} | ||
return nil | ||
}, | ||
} | ||
|
||
func startHarness() error { | ||
http.Handle("/500", new(Handler500)) | ||
http.Handle("/400", new(Handler400)) | ||
http.Handle("/huge", new(HandlerHuge)) | ||
http.Handle("/junk", new(HandlerJunk)) | ||
|
||
return http.ListenAndServe(fmt.Sprintf("%s:%d", *listenAddr, *harnessPort), nil) | ||
} | ||
|
||
func init() { | ||
zerolog.SetGlobalLevel(zerolog.TraceLevel) | ||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) | ||
harnessPort = TestHarnessCmd.PersistentFlags().Uint16("port", 11235, "If the mode is tcp level or higher this will set the port that the server listens on ") | ||
listenAddr = TestHarnessCmd.PersistentFlags().String("listen-ip", "127.0.0.1", "The IP that we'll use to listen") | ||
} | ||
|
||
func (m Handler500) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
log.Debug().Msg("handling request") | ||
w.WriteHeader(500) | ||
_, _ = w.Write([]byte(HarnessIdentifier)) | ||
} | ||
|
||
func (m Handler400) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
log.Debug().Msg("handling request") | ||
w.WriteHeader(400) | ||
_, _ = w.Write([]byte(HarnessIdentifier)) | ||
} | ||
|
||
func (m HandlerJunk) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
idxS := r.URL.Query().Get("idx") | ||
idx, err := strconv.Atoi(idxS) | ||
if err != nil { | ||
idx = rand.Intn(len(junkJSONRPC)) | ||
} | ||
|
||
w.Header().Set("Content-Type", junkContentTypeHeader[rand.Intn(len(junkContentTypeHeader))]) | ||
|
||
log.Debug().Int("idx", idx).Msg("handling request") | ||
|
||
junkResponse := junkJSONRPC[idx%len(junkJSONRPC)] | ||
w.WriteHeader(200) | ||
_, _ = w.Write([]byte(junkResponse)) | ||
} | ||
|
||
func (m HandlerHuge) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
b := r.URL.Query().Get("bytes") | ||
bc, err := strconv.Atoi(b) | ||
if err != nil { | ||
bc = 1024 * 1024 | ||
} | ||
hugeResponse := strings.Repeat("J", bc) | ||
hugeResponseStr := `{"jsonrpc": "2.0", "result": "` + hugeResponse + `", "id": 1}` | ||
log.Debug().Msg("handling request") | ||
w.WriteHeader(200) | ||
_, _ = w.Write([]byte(hugeResponseStr)) | ||
} | ||
|
||
//A server that's listening on UDP rather tha TCP | ||
//A server that responds with valid data but with a delay (e.g. a 2-second delay) | ||
//A server that returns data with invalid or malformed JSON syntax | ||
//A server that returns data in a different character encoding than expected (e.g. ISO-8859-1 instead of UTF-8) | ||
//A server that responds with a different HTTP status code than expected (e.g. 301 instead of 200) | ||
//A server that sends back a response that exceeds the content-length specified in the response header | ||
//A server that sends back a response with missing headers | ||
//A server that sends back a response with extra headers | ||
//A server that requires an authentication header, but fails if it is not provided or if it is incorrect | ||
//A server that requires a specific content type header, and fails if it is not provided or if it is incorrect | ||
//A server that has a firewall that blocks certain IP addresses, causing the request to fail. | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.