2021-12-22 07:01:30 -05:00
package pndp
import (
"fmt"
"net"
"strings"
"sync"
"time"
)
var GlobalDebug = false
2021-12-24 11:19:36 -05:00
type ResponderObj struct {
stopChan chan struct { }
stopWG * sync . WaitGroup
iface string
filter [ ] * net . IPNet
autosense string
}
type ProxyObj struct {
stopChan chan struct { }
stopWG * sync . WaitGroup
iface1 string
iface2 string
filter [ ] * net . IPNet
autosense string
2021-12-22 07:01:30 -05:00
}
2021-12-24 11:19:36 -05:00
// NewResponder
2021-12-22 07:01:30 -05:00
//
2021-12-24 11:19:36 -05:00
// iface - The interface to listen to and respond from
//
// filter - Optional (can be nil) list of CIDRs to whitelist. Must be IPV6! ParseFilter verifies ipv6
//
// With the optional autosenseInterface argument, the whitelist is configured based on the addresses assigned to the interface specified. This works even if the IP addresses change frequently.
// Start() must be called on the object to actually start responding
func NewResponder ( iface string , filter [ ] * net . IPNet , autosenseInterface string ) * ResponderObj {
2021-12-25 08:21:07 -05:00
fmt . Println ( "WARNING: You should use a whitelist for the responder unless you really know what you are doing" )
2021-12-24 11:19:36 -05:00
var s sync . WaitGroup
return & ResponderObj {
stopChan : make ( chan struct { } ) ,
stopWG : & s ,
iface : iface ,
filter : filter ,
autosense : autosenseInterface ,
2021-12-22 07:01:30 -05:00
}
}
2021-12-24 11:19:36 -05:00
func ( obj * ResponderObj ) Start ( ) {
go obj . start ( )
}
func ( obj * ResponderObj ) start ( ) {
obj . stopWG . Add ( 1 )
requests := make ( chan * ndpRequest , 100 )
defer func ( ) {
close ( requests )
obj . stopWG . Done ( )
2021-12-22 07:01:30 -05:00
} ( )
2021-12-24 16:43:49 -05:00
go respond ( obj . iface , requests , ndp_ADV , nil , obj . filter , obj . autosense , obj . stopWG , obj . stopChan )
2021-12-24 11:19:36 -05:00
go listen ( obj . iface , requests , ndp_SOL , obj . stopWG , obj . stopChan )
2021-12-24 13:02:57 -05:00
fmt . Println ( "Started responder instance on interface " , obj . iface )
2021-12-24 11:19:36 -05:00
<- obj . stopChan
}
//Stop a running Responder instance
2021-12-25 08:21:07 -05:00
// Returns false on error
2021-12-24 11:19:36 -05:00
func ( obj * ResponderObj ) Stop ( ) bool {
close ( obj . stopChan )
fmt . Println ( "Shutting down responder instance.." )
if wgWaitTimout ( obj . stopWG , 10 * time . Second ) {
fmt . Println ( "Done" )
2021-12-22 07:01:30 -05:00
return true
2021-12-24 11:19:36 -05:00
} else {
fmt . Println ( "Error shutting down instance" )
2021-12-22 07:01:30 -05:00
return false
}
}
2021-12-24 11:19:36 -05:00
// NewProxy Proxy NDP between interfaces iface1 and iface2 with an optional filter (whitelist)
2021-12-22 07:01:30 -05:00
//
2021-12-24 11:19:36 -05:00
// filter - Optional (can be nil) list of CIDRs to whitelist. Must be IPV6! ParseFilter verifies ipv6
2021-12-22 07:01:30 -05:00
//
2021-12-24 11:19:36 -05:00
// With the optional autosenseInterface argument, the whitelist is configured based on the addresses assigned to the interface specified. This works even if the IP addresses change frequently.
2021-12-22 07:01:30 -05:00
//
2021-12-24 11:19:36 -05:00
// Start() must be called on the object to actually start proxying
func NewProxy ( iface1 string , iface2 string , filter [ ] * net . IPNet , autosenseInterface string ) * ProxyObj {
var s sync . WaitGroup
return & ProxyObj {
stopChan : make ( chan struct { } ) ,
stopWG : & s ,
iface1 : iface1 ,
iface2 : iface2 ,
filter : filter ,
autosense : autosenseInterface ,
}
2021-12-22 07:01:30 -05:00
}
2021-12-24 11:19:36 -05:00
func ( obj * ProxyObj ) Start ( ) {
go obj . start ( )
}
func ( obj * ProxyObj ) start ( ) {
obj . stopWG . Add ( 1 )
defer func ( ) {
obj . stopWG . Done ( )
} ( )
2021-12-22 07:01:30 -05:00
2021-12-24 16:43:49 -05:00
out_iface1_sol_questions_iface2_adv := make ( chan * ndpQuestion , 100 )
defer close ( out_iface1_sol_questions_iface2_adv )
out_iface2_sol_questions_iface1_adv := make ( chan * ndpQuestion , 100 )
defer close ( out_iface2_sol_questions_iface1_adv )
2021-12-22 07:01:30 -05:00
req_iface1_sol_iface2 := make ( chan * ndpRequest , 100 )
defer close ( req_iface1_sol_iface2 )
2021-12-24 11:19:36 -05:00
go listen ( obj . iface1 , req_iface1_sol_iface2 , ndp_SOL , obj . stopWG , obj . stopChan )
2021-12-24 16:43:49 -05:00
go respond ( obj . iface2 , req_iface1_sol_iface2 , ndp_SOL , out_iface2_sol_questions_iface1_adv , obj . filter , obj . autosense , obj . stopWG , obj . stopChan )
2021-12-22 07:01:30 -05:00
req_iface2_sol_iface1 := make ( chan * ndpRequest , 100 )
defer close ( req_iface2_sol_iface1 )
2021-12-24 11:19:36 -05:00
go listen ( obj . iface2 , req_iface2_sol_iface1 , ndp_SOL , obj . stopWG , obj . stopChan )
2021-12-24 16:43:49 -05:00
go respond ( obj . iface1 , req_iface2_sol_iface1 , ndp_SOL , out_iface1_sol_questions_iface2_adv , nil , "" , obj . stopWG , obj . stopChan )
2021-12-22 07:01:30 -05:00
req_iface1_adv_iface2 := make ( chan * ndpRequest , 100 )
defer close ( req_iface1_adv_iface2 )
2021-12-24 11:19:36 -05:00
go listen ( obj . iface1 , req_iface1_adv_iface2 , ndp_ADV , obj . stopWG , obj . stopChan )
2021-12-24 16:43:49 -05:00
go respond ( obj . iface2 , req_iface1_adv_iface2 , ndp_ADV , out_iface1_sol_questions_iface2_adv , nil , "" , obj . stopWG , obj . stopChan )
2021-12-22 07:01:30 -05:00
req_iface2_adv_iface1 := make ( chan * ndpRequest , 100 )
defer close ( req_iface2_adv_iface1 )
2021-12-24 11:19:36 -05:00
go listen ( obj . iface2 , req_iface2_adv_iface1 , ndp_ADV , obj . stopWG , obj . stopChan )
2021-12-24 16:43:49 -05:00
go respond ( obj . iface1 , req_iface2_adv_iface1 , ndp_ADV , out_iface2_sol_questions_iface1_adv , nil , "" , obj . stopWG , obj . stopChan )
2021-12-24 11:19:36 -05:00
2021-12-24 13:02:57 -05:00
fmt . Println ( "Started Proxy instance for interfaces: " , obj . iface1 , " and " , obj . iface2 )
2021-12-24 11:19:36 -05:00
<- obj . stopChan
}
//Stop a running Proxy instance
2021-12-24 11:23:39 -05:00
// Returns false on error
2021-12-24 11:19:36 -05:00
func ( obj * ProxyObj ) Stop ( ) bool {
close ( obj . stopChan )
fmt . Println ( "Shutting down proxy instance.." )
if wgWaitTimout ( obj . stopWG , 10 * time . Second ) {
fmt . Println ( "Done" )
return true
} else {
fmt . Println ( "Error shutting down instance" )
return false
}
2021-12-22 07:01:30 -05:00
}
// ParseFilter Helper Function to Parse a string of CIDRs separated by a semicolon as a Whitelist for SimpleRespond
func ParseFilter ( f string ) [ ] * net . IPNet {
2021-12-24 11:19:36 -05:00
if f == "" {
return nil
}
2021-12-22 07:01:30 -05:00
s := strings . Split ( f , ";" )
result := make ( [ ] * net . IPNet , len ( s ) )
for i , n := range s {
_ , cidr , err := net . ParseCIDR ( n )
if err != nil {
panic ( err )
}
result [ i ] = cidr
}
return result
}
2021-12-24 11:19:36 -05:00
func wgWaitTimout ( wg * sync . WaitGroup , timeout time . Duration ) bool {
t := make ( chan struct { } )
go func ( ) {
defer close ( t )
wg . Wait ( )
} ( )
select {
case <- t :
return true
case <- time . After ( timeout ) :
return false
}
}