Skip to content

Commit 646ffb7

Browse files
authored
Release/0.8.2 (#115)
* Bump up APIFW version to 0.8.2 * Fix DNS resolver issue
1 parent 6593f3e commit 646ffb7

14 files changed

+178
-161
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION := 0.8.1
1+
VERSION := 0.8.2
22

33
.DEFAULT_GOAL := build
44

cmd/api-firewall/main.go

+32-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"context"
45
"expvar" // Register the expvar handlers
56
"fmt"
67
"mime"
@@ -777,16 +778,40 @@ func runProxyMode(logger *logrus.Logger) error {
777778
initialCap = 1
778779
}
779780

780-
var dnsCacheResolver proxy.DNSCache
781+
// default DNS resolver
782+
resolver := &net.Resolver{
783+
PreferGo: true,
784+
StrictErrors: false,
785+
}
781786

782-
// init DNS resolver
783-
if cfg.DNS.Cache {
784-
dnsCacheResolver, err = proxy.NewDNSResolver(cfg.DNS.FetchTimeout, cfg.DNS.LookupTimeout, &net.Resolver{PreferGo: true}, logger)
785-
if err != nil {
786-
return errors.Wrap(err, "DNS cache resolver init")
787+
// configuration of the custom DNS server
788+
if cfg.DNS.Nameserver.Host != "" {
789+
var builder strings.Builder
790+
builder.WriteString(cfg.DNS.Nameserver.Host)
791+
builder.WriteString(":")
792+
builder.WriteString(cfg.DNS.Nameserver.Port)
793+
794+
resolver.Dial = func(ctx context.Context, network, address string) (net.Conn, error) {
795+
d := net.Dialer{
796+
Timeout: cfg.DNS.LookupTimeout,
797+
}
798+
return d.DialContext(ctx, cfg.DNS.Nameserver.Proto, builder.String())
787799
}
788800
}
789801

802+
// init DNS resolver
803+
dnsCacheOptions := proxy.DNSCacheOptions{
804+
UseCache: cfg.DNS.Cache,
805+
Logger: logger,
806+
FetchTimeout: cfg.DNS.FetchTimeout,
807+
LookupTimeout: cfg.DNS.LookupTimeout,
808+
}
809+
810+
dnsResolver, err := proxy.NewDNSResolver(resolver, &dnsCacheOptions)
811+
if err != nil {
812+
return errors.Wrap(err, "DNS cache resolver init")
813+
}
814+
790815
options := proxy.Options{
791816
InitialPoolCapacity: initialCap,
792817
ClientPoolCapacity: cfg.Server.ClientPoolCapacity,
@@ -798,7 +823,7 @@ func runProxyMode(logger *logrus.Logger) error {
798823
DialTimeout: cfg.Server.DialTimeout,
799824
DNSConfig: cfg.DNS,
800825
}
801-
pool, err := proxy.NewChanPool(host, &options, dnsCacheResolver)
826+
pool, err := proxy.NewChanPool(host, &options, dnsResolver)
802827
if err != nil {
803828
return errors.Wrap(err, "proxy pool init")
804829
}

cmd/api-firewall/tests/main_dns_test.go

+12-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/foxcpp/go-mockdns"
1010
"github.com/sirupsen/logrus"
11+
1112
"github.com/wallarm/api-firewall/internal/config"
1213
"github.com/wallarm/api-firewall/internal/platform/proxy"
1314
)
@@ -49,13 +50,20 @@ func TestWithoutRCCDNSCacheBasic(t *testing.T) {
4950
r := &net.Resolver{}
5051
srv.PatchNet(r)
5152

52-
dnsCache, err := proxy.NewDNSResolver(cfg.DNS.FetchTimeout, cfg.DNS.LookupTimeout, r, logger)
53+
dnsResolverOptions := proxy.DNSCacheOptions{
54+
UseCache: true,
55+
Logger: logger,
56+
FetchTimeout: cfg.DNS.FetchTimeout,
57+
LookupTimeout: cfg.DNS.LookupTimeout,
58+
}
59+
60+
dnsCache, err := proxy.NewDNSResolver(r, &dnsResolverOptions)
5361
if err != nil {
5462
t.Fatal(err)
5563
}
5664
defer dnsCache.Stop()
5765

58-
addr, err := dnsCache.Fetch(context.Background(), "example.org")
66+
addr, err := dnsCache.LookupIPAddr(context.Background(), "example.org")
5967
if err != nil {
6068
t.Error(err)
6169
}
@@ -69,7 +77,7 @@ func TestWithoutRCCDNSCacheBasic(t *testing.T) {
6977

7078
time.Sleep(600 * time.Millisecond)
7179

72-
addr, err = dnsCache.Fetch(context.Background(), "example.org")
80+
addr, err = dnsCache.LookupIPAddr(context.Background(), "example.org")
7381
if err != nil {
7482
t.Error(err)
7583
}
@@ -81,7 +89,7 @@ func TestWithoutRCCDNSCacheBasic(t *testing.T) {
8189

8290
time.Sleep(800 * time.Millisecond)
8391

84-
addr, err = dnsCache.Fetch(context.Background(), "example.org")
92+
addr, err = dnsCache.LookupIPAddr(context.Background(), "example.org")
8593
if err != nil {
8694
t.Error(err)
8795
}

cmd/api-firewall/tests/main_test.go

+10-4
Original file line numberDiff line numberDiff line change
@@ -2836,8 +2836,13 @@ func (s *ServiceTests) testCustomHostHeader(t *testing.T) {
28362836
Server: serverConf,
28372837
}
28382838

2839+
ipAddrs := []net.IPAddr{}
2840+
ipAddrs = append(ipAddrs, net.IPAddr{IP: net.IPv4(127, 0, 0, 1), Zone: ""})
2841+
2842+
s.dnsCache.EXPECT().LookupIPAddr(gomock.Any(), gomock.Any()).Return(ipAddrs, nil).Times(3)
2843+
28392844
options := proxy.Options{
2840-
InitialPoolCapacity: 100,
2845+
InitialPoolCapacity: 1,
28412846
ClientPoolCapacity: cfg.Server.ClientPoolCapacity,
28422847
InsecureConnection: cfg.Server.InsecureConnection,
28432848
RootCA: cfg.Server.RootCA,
@@ -2846,7 +2851,7 @@ func (s *ServiceTests) testCustomHostHeader(t *testing.T) {
28462851
WriteTimeout: cfg.Server.WriteTimeout,
28472852
DialTimeout: cfg.Server.DialTimeout,
28482853
}
2849-
pool, err := proxy.NewChanPool("localhost:28290", &options, nil)
2854+
pool, err := proxy.NewChanPool("localhost:28290", &options, s.dnsCache)
28502855
if err != nil {
28512856
t.Fatal(err)
28522857
}
@@ -2944,9 +2949,10 @@ func (s *ServiceTests) testDNSCacheFetch(t *testing.T) {
29442949
}
29452950

29462951
localIP := net.ParseIP("127.0.0.1")
2947-
ips := []net.IP{localIP}
2952+
ipAddrs := []net.IPAddr{}
2953+
ipAddrs = append(ipAddrs, net.IPAddr{IP: localIP, Zone: ""})
29482954

2949-
s.dnsCache.EXPECT().Fetch(gomock.Any(), gomock.Any()).Return(ips, nil).Times(3)
2955+
s.dnsCache.EXPECT().LookupIPAddr(gomock.Any(), gomock.Any()).Return(ipAddrs, nil).Times(3)
29502956

29512957
pool, err := proxy.NewChanPool("localhost:28290", &options, s.dnsCache)
29522958
if err != nil {
0 Bytes
Binary file not shown.

demo/docker-compose/OWASP_CoreRuleSet/docker-compose.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ version: "3.8"
22
services:
33
api-firewall:
44
container_name: api-firewall
5-
image: wallarm/api-firewall:v0.8.1
5+
image: wallarm/api-firewall:v0.8.2
66
restart: on-failure
77
environment:
88
APIFW_URL: "http://0.0.0.0:8080"

demo/docker-compose/docker-compose-api-mode.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ version: '3.8'
22
services:
33
api-firewall:
44
container_name: api-firewall
5-
image: wallarm/api-firewall:v0.8.1
5+
image: wallarm/api-firewall:v0.8.2
66
restart: on-failure
77
environment:
88
APIFW_MODE: "api"

demo/docker-compose/docker-compose-graphql-mode.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ version: '3.8'
22
services:
33
api-firewall:
44
container_name: api-firewall
5-
image: wallarm/api-firewall:v0.8.1
5+
image: wallarm/api-firewall:v0.8.2
66
restart: on-failure
77
environment:
88
APIFW_MODE: "graphql"

demo/docker-compose/docker-compose.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ version: "3.8"
22
services:
33
api-firewall:
44
container_name: api-firewall
5-
image: wallarm/api-firewall:v0.8.1
5+
image: wallarm/api-firewall:v0.8.2
66
restart: on-failure
77
environment:
88
APIFW_URL: "http://0.0.0.0:8080"

docs/release-notes.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
This page describes new releases of Wallarm API Firewall.
44

5+
## v0.8.2 (2024-09-24)
6+
7+
* Fixed DNS resolver cache issue
8+
59
## v0.8.1 (2024-09-13)
610

711
* Fixed incorrect request to get API specification structure issue

helm/api-firewall/Chart.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apiVersion: v1
22
name: api-firewall
33
version: 0.7.1
4-
appVersion: 0.8.1
4+
appVersion: 0.8.2
55
description: Wallarm OpenAPI-based API Firewall
66
home: https://github.com/wallarm/api-firewall
77
icon: https://static.wallarm.com/wallarm-logo.svg

internal/platform/proxy/chainpool.go

+35-61
Original file line numberDiff line numberDiff line change
@@ -21,39 +21,32 @@ import (
2121
"github.com/wallarm/api-firewall/internal/config"
2222
)
2323

24+
const defaultConcurrency = 1000
25+
2426
var (
2527
errInvalidCapacitySetting = errors.New("invalid capacity settings")
26-
errClosed = errors.New("err: chan closed")
28+
errClosed = errors.New("chan closed")
29+
errInvalidDNSResolver = errors.New("invalid DNS resolver")
2730
)
2831

2932
func (p *chanPool) tryResolveAndFetchOneIP(host string) (string, error) {
3033

31-
var ips []net.IP
3234
var resolvedIP string
33-
var err error
3435

35-
if p.dnsCacheResolver != nil {
36-
ips, err = p.dnsCacheResolver.Fetch(context.Background(), host)
37-
if err != nil {
38-
return "", err
39-
}
40-
} else {
41-
// resolve host using local resolver
42-
ips, err = p.defaultResolver.LookupIP(context.Background(), "ip", host)
43-
if err != nil {
44-
return "", err
45-
}
36+
ipAddrs, err := p.dnsResolver.LookupIPAddr(context.Background(), host)
37+
if err != nil {
38+
return "", err
4639
}
4740

48-
for _, ip := range ips {
49-
if ip.To4() != nil {
41+
for _, ip := range ipAddrs {
42+
if ip.IP.To4() != nil {
5043
resolvedIP = ip.String()
5144
return resolvedIP, nil
5245
}
5346
}
5447

55-
for _, ip := range ips {
56-
if ip.To16() != nil {
48+
for _, ip := range ipAddrs {
49+
if ip.IP.To16() != nil {
5750
resolvedIP = ip.String()
5851
return resolvedIP, nil
5952
}
@@ -73,21 +66,19 @@ func (p *chanPool) factory(connAddr string) HTTPClient {
7366
DisableHeaderNamesNormalizing: true,
7467
DisablePathNormalizing: true,
7568
Dial: func(addr string) (net.Conn, error) {
76-
return fasthttp.DialTimeout(connAddr, p.options.DialTimeout)
69+
tcpDialer := &fasthttp.TCPDialer{
70+
Concurrency: defaultConcurrency,
71+
Resolver: p.dnsResolver,
72+
DisableDNSResolution: p.options.DNSConfig.Cache,
73+
}
74+
return tcpDialer.DialTimeout(connAddr, p.options.DialTimeout)
7775
},
7876
TLSConfig: p.tlsConfig,
7977
MaxConnsPerHost: p.options.MaxConnsPerHost,
8078
ReadTimeout: p.options.ReadTimeout,
8179
WriteTimeout: p.options.WriteTimeout,
8280
}
8381

84-
// use configured NS
85-
if p.options.DNSConfig.Nameserver.Host != "" {
86-
proxyClient.Dial = (&fasthttp.TCPDialer{
87-
Resolver: p.defaultResolver,
88-
}).Dial
89-
}
90-
9182
return &proxyClient
9283
}
9384

@@ -121,9 +112,8 @@ type chanPool struct {
121112
initResolvedIP string
122113
initConnAddr string
123114

124-
tlsConfig *tls.Config
125-
defaultResolver *net.Resolver
126-
dnsCacheResolver DNSCache
115+
tlsConfig *tls.Config
116+
dnsResolver DNSCache
127117
}
128118

129119
type Options struct {
@@ -140,11 +130,15 @@ type Options struct {
140130
}
141131

142132
// NewChanPool to new a pool with some params
143-
func NewChanPool(hostAddr string, options *Options, dnsCacheResolver DNSCache) (Pool, error) {
133+
func NewChanPool(hostAddr string, options *Options, dnsResolver DNSCache) (Pool, error) {
144134
if options.InitialPoolCapacity < 0 || options.ClientPoolCapacity <= 0 || options.InitialPoolCapacity > options.ClientPoolCapacity {
145135
return nil, errInvalidCapacitySetting
146136
}
147137

138+
if dnsResolver == nil {
139+
return nil, errInvalidDNSResolver
140+
}
141+
148142
// Get the SystemCertPool, continue with an empty pool on error
149143
rootCAs, err := x509.SystemCertPool()
150144
if err != nil {
@@ -182,23 +176,7 @@ func NewChanPool(hostAddr string, options *Options, dnsCacheResolver DNSCache) (
182176
host: host,
183177
port: port,
184178
tlsConfig: tlsConfig,
185-
defaultResolver: &net.Resolver{
186-
PreferGo: true,
187-
},
188-
dnsCacheResolver: dnsCacheResolver,
189-
}
190-
191-
// init NS in the DNS resolver
192-
if options.DNSConfig.Nameserver.Host != "" {
193-
var builder strings.Builder
194-
builder.WriteString(options.DNSConfig.Nameserver.Host)
195-
builder.WriteString(":")
196-
builder.WriteString(options.DNSConfig.Nameserver.Port)
197-
198-
pool.defaultResolver.Dial = func(ctx context.Context, network, address string) (net.Conn, error) {
199-
d := net.Dialer{}
200-
return d.DialContext(ctx, options.DNSConfig.Nameserver.Proto, builder.String())
201-
}
179+
dnsResolver: dnsResolver,
202180
}
203181

204182
ip, err := pool.tryResolveAndFetchOneIP(host)
@@ -220,20 +198,18 @@ func NewChanPool(hostAddr string, options *Options, dnsCacheResolver DNSCache) (
220198

221199
connAddr := pool.initConnAddr
222200

223-
if pool.dnsCacheResolver != nil {
224-
ip, err = pool.tryResolveAndFetchOneIP(pool.host)
225-
if err != nil {
226-
continue
227-
}
201+
ip, err = pool.tryResolveAndFetchOneIP(pool.host)
202+
if err != nil {
203+
continue
204+
}
228205

229-
builder.Reset()
206+
builder.Reset()
230207

231-
builder.WriteString(ip)
232-
builder.WriteString(":")
233-
builder.WriteString(port)
208+
builder.WriteString(ip)
209+
builder.WriteString(":")
210+
builder.WriteString(port)
234211

235-
connAddr = builder.String()
236-
}
212+
connAddr = builder.String()
237213

238214
proxy := pool.factory(connAddr)
239215
if pool.reverseProxyChanLB[ip] == nil {
@@ -261,9 +237,7 @@ func (p *chanPool) Close() {
261237
close(reverseProxyChan)
262238
}
263239

264-
if p.dnsCacheResolver != nil {
265-
p.dnsCacheResolver.Stop()
266-
}
240+
p.dnsResolver.Stop()
267241

268242
}
269243

0 commit comments

Comments
 (0)