Skip to content

Commit 4dd4738

Browse files
authored
Merge pull request #31 from joomcode/feature/ignore-zero-address
Ignore zero addresses in CLUSTER SLOTS response
2 parents c558557 + 090aef1 commit 4dd4738

File tree

2 files changed

+195
-4
lines changed

2 files changed

+195
-4
lines changed

rediscluster/redisclusterutil/cluster.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,21 @@ func ParseSlotsInfo(res interface{}) ([]SlotsRange, error) {
7272
for j := 2; j < len(rawrange); j++ {
7373
rawaddr, ok := rawrange[j].([]interface{})
7474
if !ok || len(rawaddr) < 2 {
75-
return errf("address format mismatch: res[%d][%d] = %+v",
75+
return errf("address format mismatch: res[%d][%d] = %+v, missing lines",
7676
i, j, rawrange[j])
7777
}
78-
host, ok := rawaddr[0].([]byte)
79-
port, ok2 := rawaddr[1].(int64)
80-
if !ok || !ok2 || port <= 0 || port+10000 > 65535 {
78+
host, hasHost := rawaddr[0].([]byte)
79+
port, hasPort := rawaddr[1].(int64)
80+
if !hasHost && hasPort && port == 0 {
81+
// Due to possible Redis cluster misconfiguration we can receive zero address
82+
// for one of the replicas. It is totally fine to skip the misconfigured replica
83+
// and go with the remaining ones without inducing denial of service.
84+
arr, isArray := rawaddr[0].([]interface{})
85+
if isArray && len(arr) == 0 {
86+
continue
87+
}
88+
}
89+
if !hasHost || !hasPort || port <= 0 || port+10000 > 65535 {
8190
return errf("address format mismatch: res[%d][%d] = %+v",
8291
i, j, rawaddr)
8392
}
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package redisclusterutil
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestParseSlotsInfo(t *testing.T) {
11+
clusterSlotsResponse := []interface{}{
12+
[]interface{}{
13+
int64(0),
14+
int64(5460),
15+
[]interface{}{
16+
[]byte("127.0.0.1"),
17+
int64(30001),
18+
[]byte("09dbe9720cda62f7865eabc5fd8857c5d2678366"),
19+
[]interface{}{
20+
"hostname",
21+
"host-1.redis.example.com",
22+
},
23+
},
24+
[]interface{}{
25+
[]byte("127.0.0.1"),
26+
int64(30004),
27+
[]byte("821d8ca00d7ccf931ed3ffc7e3db0599d2271abf"),
28+
[]interface{}{
29+
"hostname",
30+
"host-2.redis.example.com",
31+
},
32+
},
33+
},
34+
[]interface{}{
35+
int64(5461),
36+
int64(10922),
37+
[]interface{}{
38+
[]byte("127.0.0.1"),
39+
int64(30002),
40+
[]byte("c9d93d9f2c0c524ff34cc11838c2003d8c29e013"),
41+
[]interface{}{
42+
"hostname",
43+
"host-3.redis.example.com",
44+
},
45+
},
46+
[]interface{}{
47+
[]byte("127.0.0.1"),
48+
int64(30005),
49+
[]byte("faadb3eb99009de4ab72ad6b6ed87634c7ee410f"),
50+
[]interface{}{
51+
"hostname",
52+
"host-4.redis.example.com",
53+
},
54+
},
55+
},
56+
[]interface{}{
57+
int64(10923),
58+
int64(16383),
59+
[]interface{}{
60+
[]byte("192.168.11.131"),
61+
int64(30003),
62+
[]byte("044ec91f325b7595e76dbcb18cc688b6a5b434a1"),
63+
[]interface{}{
64+
"hostname",
65+
"host-5.redis.example.com",
66+
},
67+
},
68+
[]interface{}{
69+
[]byte("127.0.0.1"),
70+
int64(30006),
71+
[]byte("58e6e48d41228013e5d9c1c37c5060693925e97e"),
72+
[]interface{}{
73+
"hostname",
74+
"host-6.redis.example.com",
75+
},
76+
},
77+
},
78+
}
79+
80+
expectedSlots := []SlotsRange{
81+
{
82+
From: 0,
83+
To: 5460,
84+
Addrs: []string{
85+
"127.0.0.1:30001",
86+
"127.0.0.1:30004",
87+
},
88+
},
89+
{
90+
From: 5461,
91+
To: 10922,
92+
Addrs: []string{
93+
"127.0.0.1:30002",
94+
"127.0.0.1:30005",
95+
},
96+
},
97+
{
98+
From: 10923,
99+
To: 16383,
100+
Addrs: []string{
101+
"192.168.11.131:30003",
102+
"127.0.0.1:30006",
103+
},
104+
},
105+
}
106+
107+
slots, err := ParseSlotsInfo(clusterSlotsResponse)
108+
require.NoError(t, err)
109+
110+
assert.Equal(t, expectedSlots, slots)
111+
}
112+
113+
func TestParseSlotsInfo_EmptyAddress(t *testing.T) {
114+
clusterSlotsResponse := []interface{}{
115+
[]interface{}{
116+
int64(0),
117+
int64(5460),
118+
[]interface{}{
119+
[]byte("127.0.0.1"),
120+
int64(30001),
121+
[]byte("09dbe9720cda62f7865eabc5fd8857c5d2678366"),
122+
[]interface{}{
123+
"hostname",
124+
"host-1.redis.example.com",
125+
},
126+
},
127+
[]interface{}{
128+
[]interface{}{},
129+
int64(0),
130+
[]byte("821d8ca00d7ccf931ed3ffc7e3db0599d2271abf"),
131+
[]interface{}{
132+
"hostname",
133+
"host-2.redis.example.com",
134+
},
135+
},
136+
},
137+
[]interface{}{
138+
int64(5461),
139+
int64(10922),
140+
[]interface{}{
141+
[]interface{}{},
142+
int64(0),
143+
[]byte("c9d93d9f2c0c524ff34cc11838c2003d8c29e013"),
144+
[]interface{}{
145+
"hostname",
146+
"host-3.redis.example.com",
147+
},
148+
},
149+
[]interface{}{
150+
[]byte("127.0.0.1"),
151+
int64(30005),
152+
[]byte("faadb3eb99009de4ab72ad6b6ed87634c7ee410f"),
153+
[]interface{}{
154+
"hostname",
155+
"host-4.redis.example.com",
156+
},
157+
},
158+
},
159+
}
160+
161+
expectedSlots := []SlotsRange{
162+
{
163+
From: 0,
164+
To: 5460,
165+
Addrs: []string{
166+
"127.0.0.1:30001",
167+
},
168+
},
169+
{
170+
From: 5461,
171+
To: 10922,
172+
Addrs: []string{
173+
"127.0.0.1:30005",
174+
},
175+
},
176+
}
177+
178+
slots, err := ParseSlotsInfo(clusterSlotsResponse)
179+
require.NoError(t, err)
180+
181+
assert.Equal(t, expectedSlots, slots)
182+
}

0 commit comments

Comments
 (0)