Update comments
This commit is contained in:
parent
489d5ba9cc
commit
6673f69913
14
config.go
14
config.go
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// config accepts a slice of type Redirect and returns an error
|
// config accepts a slice of type Redirect and returns an error
|
||||||
// it organizes the data from the input redirects in a way that makes sense for FortiOS objects
|
// it organizes the input data in a way that makes sense for FortiOS objects
|
||||||
// then outputs the configuration to stdout
|
// then outputs the configuration to stdout
|
||||||
func config(redirects []Redirect) error {
|
func config(redirects []Redirect) error {
|
||||||
|
|
||||||
@ -16,16 +16,18 @@ func config(redirects []Redirect) error {
|
|||||||
|
|
||||||
// Iterate over all redirects and output url-rewrite-rules
|
// Iterate over all redirects and output url-rewrite-rules
|
||||||
|
|
||||||
fmt.Printf("\n\n------------------------\n\n\n")
|
fmt.Printf("\n\n------------------------ COPY BELOW THIS LINE ------------------------\n\n\n")
|
||||||
fmt.Println("config waf url-rewrite url-rewrite-rule")
|
fmt.Println("config waf url-rewrite url-rewrite-rule")
|
||||||
for _, redirect := range redirects {
|
for _, redirect := range redirects {
|
||||||
|
|
||||||
|
// Parse the source URL string into a URL object so we can extract features
|
||||||
sourceURL, err := url.Parse(redirect.sourceURL)
|
sourceURL, err := url.Parse(redirect.sourceURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to parse source URL '%s': %v", redirect.sourceURL, err)
|
return fmt.Errorf("unable to parse source URL '%s': %v", redirect.sourceURL, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ruleName, action string
|
var ruleName, action string
|
||||||
if len(redirect.sourceURL) > 63 { // FortiOS only allows up to 63 characters
|
if len(redirect.sourceURL) > 63 { // FortiOS only allows up to 63 characters. There is potention for collission here. TBD: Reduce and replace characters in the middle of string with '...' and show characters at the end of the URL to make differentiation easier for operators of the WAF
|
||||||
ruleName = redirect.sourceURL[:62]
|
ruleName = redirect.sourceURL[:62]
|
||||||
} else {
|
} else {
|
||||||
ruleName = redirect.sourceURL
|
ruleName = redirect.sourceURL
|
||||||
@ -37,6 +39,7 @@ func config(redirects []Redirect) error {
|
|||||||
action = "redirect"
|
action = "redirect"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Output FortiOS configuration syntax
|
||||||
fmt.Printf("edit \"%s\"\n", ruleName)
|
fmt.Printf("edit \"%s\"\n", ruleName)
|
||||||
fmt.Printf("set location %s\n", redirect.destinationURL)
|
fmt.Printf("set location %s\n", redirect.destinationURL)
|
||||||
fmt.Printf("set action %s\n", action)
|
fmt.Printf("set action %s\n", action)
|
||||||
@ -50,11 +53,12 @@ func config(redirects []Redirect) error {
|
|||||||
fmt.Println("end")
|
fmt.Println("end")
|
||||||
fmt.Println("next")
|
fmt.Println("next")
|
||||||
|
|
||||||
// Add this rule to the policy map
|
// Add this rule to the slice inside the policy map. This is used to organize data for creating the url-rewrite-policy configuration below
|
||||||
redirectPolicies[sourceURL.Host] = append(redirectPolicies[sourceURL.Host], ruleName)
|
redirectPolicies[sourceURL.Host] = append(redirectPolicies[sourceURL.Host], ruleName)
|
||||||
}
|
}
|
||||||
fmt.Println("end")
|
fmt.Println("end")
|
||||||
|
|
||||||
|
// Output url-rewrite-policy configuration.
|
||||||
// Iterate over values in the policy map and output the policy configuration
|
// Iterate over values in the policy map and output the policy configuration
|
||||||
fmt.Println("config waf url-rewrite url-rewrite-policy")
|
fmt.Println("config waf url-rewrite url-rewrite-policy")
|
||||||
for policyName, policyRules := range redirectPolicies {
|
for policyName, policyRules := range redirectPolicies {
|
||||||
@ -68,7 +72,7 @@ func config(redirects []Redirect) error {
|
|||||||
fmt.Println("end")
|
fmt.Println("end")
|
||||||
fmt.Println("next")
|
fmt.Println("next")
|
||||||
}
|
}
|
||||||
fmt.Println("end")
|
fmt.Printf("end\n\n\n")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
4
main.go
4
main.go
@ -64,12 +64,12 @@ func main() {
|
|||||||
|
|
||||||
// Determine the next steps
|
// Determine the next steps
|
||||||
if *action == "config" {
|
if *action == "config" {
|
||||||
err := config(redirects)
|
err := config(redirects) // Function defined in config.go
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to build configuration: %v", err)
|
log.Fatalf("failed to build configuration: %v", err)
|
||||||
}
|
}
|
||||||
} else if *action == "test" {
|
} else if *action == "test" {
|
||||||
err := test(redirects)
|
err := test(redirects) // Function defined in test.go
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to test redirects: %v", err)
|
log.Fatalf("failed to test redirects: %v", err)
|
||||||
}
|
}
|
||||||
|
31
test.go
31
test.go
@ -12,21 +12,28 @@ var sem chan Empty // semaphore to limit requess in flight
|
|||||||
// test accepts a slice of type Redirect and returns an error
|
// test accepts a slice of type Redirect and returns an error
|
||||||
// it performs actual HTTP GET requests on each source URL and validates that a redirect occurs
|
// it performs actual HTTP GET requests on each source URL and validates that a redirect occurs
|
||||||
// to the destination URL and that the redirect type/status code is correct
|
// to the destination URL and that the redirect type/status code is correct
|
||||||
|
// This function makes use of concurrent requests to speed up testing.
|
||||||
func test(redirects []Redirect) error {
|
func test(redirects []Redirect) error {
|
||||||
|
|
||||||
wg := &sync.WaitGroup{}
|
// This string will hold output for any failed tests. It's displayed when all tests have completed
|
||||||
mu := &sync.Mutex{}
|
|
||||||
var summaryOutput string
|
var summaryOutput string
|
||||||
|
|
||||||
sem = make(Semaphore, *maxConcurrentRequests)
|
// Set up some tools to handle concurrency
|
||||||
|
wg := &sync.WaitGroup{} // Used to wait for all tests to finish
|
||||||
|
mu := &sync.Mutex{} // Used to lock shared memory in critical sections
|
||||||
|
sem = make(Semaphore, *maxConcurrentRequests) // Used to limit resources while having all requests queued up
|
||||||
|
|
||||||
|
// Loop through all redirects and queue them up
|
||||||
for _, redirect := range redirects {
|
for _, redirect := range redirects {
|
||||||
wg.Add(1)
|
wg.Add(1) // Add 1 resource to waitgroup
|
||||||
P(1)
|
P(1) // Take 1 resource from semaphore
|
||||||
|
|
||||||
|
// This anonymous function executes in a separate go routine and can run concurrently
|
||||||
go func(redirect Redirect) {
|
go func(redirect Redirect) {
|
||||||
defer V(1)
|
defer V(1) // If function exits (error or otherwise), put 1 resource back into semaphore
|
||||||
defer wg.Done()
|
defer wg.Done() // If function exits (error or otherwise), subtract 1 resource from waitgroup
|
||||||
|
|
||||||
|
// Create an HTTP client and override CheckRedirect to return the last response error so we can check the redirect type
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||||
return http.ErrUseLastResponse
|
return http.ErrUseLastResponse
|
||||||
@ -46,33 +53,35 @@ func test(redirects []Redirect) error {
|
|||||||
|
|
||||||
// Check the status code
|
// Check the status code
|
||||||
if resp.StatusCode != redirect.statusCode {
|
if resp.StatusCode != redirect.statusCode {
|
||||||
// Modifying output is critical section
|
// Modifying summaryOutput is critical section
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
summaryOutput += fmt.Sprintf("redirect for source URL '%s': expected status code'%d': got '%d\n", redirect.sourceURL, redirect.statusCode, resp.StatusCode)
|
summaryOutput += fmt.Sprintf("redirect for source URL '%s': expected status code'%d': got '%d\n", redirect.sourceURL, redirect.statusCode, resp.StatusCode)
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the redirect went to the correct location
|
// Parse response location URL from header into URL object
|
||||||
destURL, err := resp.Location()
|
destURL, err := resp.Location()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("failed to parse response location to URL: %v", err)
|
log.Printf("failed to parse response location to URL: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that the redirect went to the correct location
|
||||||
if destURL.String() != redirect.destinationURL {
|
if destURL.String() != redirect.destinationURL {
|
||||||
// Modifying output is critical section
|
// Modifying summyarOutput is critical section
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
summaryOutput += fmt.Sprintf("redirect for source URL '%s': expected '%s': got '%s\n", redirect.sourceURL, redirect.destinationURL, destURL.String())
|
summaryOutput += fmt.Sprintf("redirect for source URL '%s': expected '%s': got '%s\n", redirect.sourceURL, redirect.destinationURL, destURL.String())
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
}(redirect)
|
}(redirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for all tests to complete
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
fmt.Printf("\ndone tests.\n---------------------------------------------\n")
|
fmt.Printf("\ndone tests.\n---------------------------------------------\n")
|
||||||
|
|
||||||
|
// Display summaryOutput if any tests failed
|
||||||
if len(summaryOutput) > 0 {
|
if len(summaryOutput) > 0 {
|
||||||
fmt.Printf("Summary:\n\n%s", summaryOutput)
|
fmt.Printf("Summary:\n\n%s", summaryOutput)
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user