@@ -2,75 +2,159 @@ package TraefikIPRules
22
33import (
44 "context"
5+ "fmt"
56 "net"
67 "net/http"
78 "strings"
89)
910
1011type Config struct {
11- DenyList []string `json:"denyList,omitempty"`
12- AllowList []string `json:"allowList,omitempty"`
12+ Deny []string `json:"deny,omitempty"`
13+ Allow []string `json:"allow,omitempty"`
14+ Precedence string `json:"precedence,omitempty"` // "allow" or "deny"
15+ }
16+
17+ type ipRange struct {
18+ start net.IP
19+ end net.IP
1320}
1421
1522func CreateConfig () * Config {
1623 return & Config {
17- DenyList : make ([]string , 0 ),
18- AllowList : make ([]string , 0 ),
24+ Deny : make ([]string , 0 ),
25+ Allow : make ([]string , 0 ),
26+ Precedence : "deny" , // Default to deny
1927 }
2028}
2129
2230type IPProcessor struct {
23- next http.Handler
24- name string
25- denyCIDRs []* net.IPNet
26- denyIPs []net.IP
27- allowCIDRs []* net.IPNet
28- allowIPs []net.IP
31+ next http.Handler
32+ name string
33+ denyCIDRs []* net.IPNet
34+ denyIPs []net.IP
35+ denyRanges []ipRange
36+ allowCIDRs []* net.IPNet
37+ allowIPs []net.IP
38+ allowRanges []ipRange
39+ precedence string
40+ }
41+
42+ func parseIPRange (ipRangeStr string ) (* ipRange , error ) {
43+ parts := strings .Split (ipRangeStr , "-" )
44+ if len (parts ) != 2 {
45+ return nil , fmt .Errorf ("invalid IP range format: %s" , ipRangeStr )
46+ }
47+
48+ start := net .ParseIP (strings .TrimSpace (parts [0 ]))
49+ end := net .ParseIP (strings .TrimSpace (parts [1 ]))
50+
51+ if start == nil || end == nil {
52+ return nil , fmt .Errorf ("invalid IP address in range: %s" , ipRangeStr )
53+ }
54+
55+ if start .To4 () == nil || end .To4 () == nil {
56+ return nil , fmt .Errorf ("only IPv4 ranges are supported: %s" , ipRangeStr )
57+ }
58+
59+ for i := 0 ; i < len (start .To4 ()); i ++ {
60+ if start .To4 ()[i ] > end .To4 ()[i ] {
61+ return nil , fmt .Errorf ("invalid range: start IP must be less than end IP" )
62+ }
63+ if start .To4 ()[i ] < end .To4 ()[i ] {
64+ break
65+ }
66+ }
67+
68+ return & ipRange {
69+ start : start .To4 (),
70+ end : end .To4 (),
71+ }, nil
72+ }
73+
74+ func (r * ipRange ) IPRangeContains (ip net.IP ) bool {
75+ if ip .To4 () == nil {
76+ return false
77+ }
78+
79+ ip = ip .To4 ()
80+ for i := 0 ; i < 4 ; i ++ {
81+ if ip [i ] < r .start [i ] || ip [i ] > r .end [i ] {
82+ return false
83+ }
84+ if ip [i ] > r .start [i ] || ip [i ] < r .end [i ] {
85+ break
86+ }
87+ }
88+ return true
2989}
3090
3191func New (ctx context.Context , next http.Handler , config * Config , name string ) (http.Handler , error ) {
92+ if config .Precedence != "" && config .Precedence != "allow" && config .Precedence != "deny" {
93+ return nil , fmt .Errorf ("invalid precedence value: %s. Must be either 'allow' or 'deny'" , config .Precedence )
94+ }
95+
3296 processor := & IPProcessor {
33- next : next ,
34- name : name ,
97+ next : next ,
98+ name : name ,
99+ precedence : config .Precedence ,
35100 }
36101
37102 // Process deny rules
38- for _ , rule := range config .DenyList {
103+ for _ , rule := range config .Deny {
104+ // Try parsing as a single IP
39105 if ip := net .ParseIP (rule ); ip != nil {
40106 processor .denyIPs = append (processor .denyIPs , ip )
41107 continue
42108 }
43109
110+ // Try parsing as CIDR
44111 _ , network , err := net .ParseCIDR (rule )
45- if err != nil {
46- return nil , err
112+ if err == nil {
113+ processor .denyCIDRs = append (processor .denyCIDRs , network )
114+ continue
47115 }
48- processor .denyCIDRs = append (processor .denyCIDRs , network )
116+
117+ // Try parsing as IP range
118+ ipRange , err := parseIPRange (rule )
119+ if err == nil {
120+ processor .denyRanges = append (processor .denyRanges , * ipRange )
121+ continue
122+ }
123+
124+ return nil , fmt .Errorf ("invalid IP, CIDR, or range in deny list: %s" , rule )
49125 }
50126
51127 // Process allow rules
52- for _ , rule := range config .AllowList {
128+ for _ , rule := range config .Allow {
129+ // Try parsing as a single IP
53130 if ip := net .ParseIP (rule ); ip != nil {
54131 processor .allowIPs = append (processor .allowIPs , ip )
55132 continue
56133 }
57134
135+ // Try parsing as CIDR
58136 _ , network , err := net .ParseCIDR (rule )
59- if err != nil {
60- return nil , err
137+ if err == nil {
138+ processor .allowCIDRs = append (processor .allowCIDRs , network )
139+ continue
61140 }
62- processor .allowCIDRs = append (processor .allowCIDRs , network )
141+
142+ // Try parsing as IP range
143+ ipRange , err := parseIPRange (rule )
144+ if err == nil {
145+ processor .allowRanges = append (processor .allowRanges , * ipRange )
146+ continue
147+ }
148+
149+ return nil , fmt .Errorf ("invalid IP, CIDR, or range in allow list: %s" , rule )
63150 }
64151
65152 return processor , nil
66153}
67154
68- // getIP extracts the client IP from the request
69155func (p * IPProcessor ) getIP (req * http.Request ) net.IP {
70- // First try X-Forwarded-For header
71156 xff := req .Header .Get ("X-Forwarded-For" )
72157 if xff != "" {
73- // Get the first IP in the chain
74158 ips := strings .Split (xff , "," )
75159 if len (ips ) > 0 {
76160 if ip := net .ParseIP (strings .TrimSpace (ips [0 ])); ip != nil {
@@ -79,10 +163,8 @@ func (p *IPProcessor) getIP(req *http.Request) net.IP {
79163 }
80164 }
81165
82- // Fall back to RemoteAddr
83166 host , _ , err := net .SplitHostPort (req .RemoteAddr )
84167 if err != nil {
85- // Try RemoteAddr as-is
86168 if ip := net .ParseIP (req .RemoteAddr ); ip != nil {
87169 return ip
88170 }
@@ -92,53 +174,84 @@ func (p *IPProcessor) getIP(req *http.Request) net.IP {
92174 return net .ParseIP (host )
93175}
94176
95- func (p * IPProcessor ) ServeHTTP (rw http.ResponseWriter , req * http.Request ) {
96- // Get client IP
97- clientIP := p .getIP (req )
98- if clientIP == nil {
99- http .Error (rw , "Invalid IP address" , http .StatusForbidden )
100- return
101- }
102-
103- // Check deny rules first
177+ func (p * IPProcessor ) checkIPInDenyList (clientIP net.IP ) bool {
104178 for _ , denyIP := range p .denyIPs {
105179 if denyIP .Equal (clientIP ) {
106- http .Error (rw , "Access denied" , http .StatusForbidden )
107- return
180+ return true
108181 }
109182 }
110183
111184 for _ , denyCIDR := range p .denyCIDRs {
112185 if denyCIDR .Contains (clientIP ) {
113- http .Error (rw , "Access denied" , http .StatusForbidden )
114- return
186+ return true
115187 }
116188 }
117189
118- // If there are allow rules, the IP must match at least one
119- if len (p .allowIPs ) > 0 || len (p .allowCIDRs ) > 0 {
120- allowed := false
190+ for _ , denyRange := range p .denyRanges {
191+ if denyRange .IPRangeContains (clientIP ) {
192+ return true
193+ }
194+ }
121195
122- for _ , allowIP := range p .allowIPs {
123- if allowIP .Equal (clientIP ) {
124- allowed = true
125- break
126- }
196+ return false
197+ }
198+
199+ func (p * IPProcessor ) checkIPInAllowList (clientIP net.IP ) bool {
200+ if len (p .allowIPs ) == 0 && len (p .allowCIDRs ) == 0 && len (p .allowRanges ) == 0 {
201+ return false
202+ }
203+
204+ for _ , allowIP := range p .allowIPs {
205+ if allowIP .Equal (clientIP ) {
206+ return true
127207 }
208+ }
128209
129- if ! allowed {
130- for _ , allowCIDR := range p .allowCIDRs {
131- if allowCIDR .Contains (clientIP ) {
132- allowed = true
133- break
134- }
135- }
210+ for _ , allowCIDR := range p .allowCIDRs {
211+ if allowCIDR .Contains (clientIP ) {
212+ return true
213+ }
214+ }
215+
216+ for _ , allowRange := range p .allowRanges {
217+ if allowRange .IPRangeContains (clientIP ) {
218+ return true
136219 }
220+ }
221+
222+ return false
223+ }
137224
138- if ! allowed {
139- http .Error (rw , "Access denied" , http .StatusForbidden )
140- return
225+ func (p * IPProcessor ) ServeHTTP (rw http.ResponseWriter , req * http.Request ) {
226+ clientIP := p .getIP (req )
227+ if clientIP == nil {
228+ http .Error (rw , "Invalid IP address" , http .StatusForbidden )
229+ return
230+ }
231+
232+ var allowed bool
233+
234+ if p .precedence == "allow" {
235+ if p .checkIPInAllowList (clientIP ) {
236+ allowed = true
237+ } else if p .checkIPInDenyList (clientIP ) {
238+ allowed = false
239+ } else {
240+ allowed = false
141241 }
242+ } else {
243+ if p .checkIPInDenyList (clientIP ) {
244+ allowed = false
245+ } else if p .checkIPInAllowList (clientIP ) {
246+ allowed = true
247+ } else {
248+ allowed = false
249+ }
250+ }
251+
252+ if ! allowed {
253+ http .Error (rw , "Access denied" , http .StatusForbidden )
254+ return
142255 }
143256
144257 p .next .ServeHTTP (rw , req )
0 commit comments