blob: 3cafbc32fd2aaf43f16613a8af57fa1c02980bcf [file]
#!/usr/bin/env bash
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
. ./t/cli/common.sh
# Test TCP port range (nginx native range syntax)
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- "2000-2005"
' > conf/config.yaml
make init
if ! grep "listen 2000-2005" conf/nginx.conf > /dev/null; then
echo "failed: TCP port range not found in nginx.conf"
exit 1
fi
echo "passed: TCP port range"
# Test UDP port range
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- 9100
udp:
- "9300-9305"
' > conf/config.yaml
make init
if ! grep "listen 9300-9305 udp" conf/nginx.conf > /dev/null; then
echo "failed: UDP port range not found in nginx.conf"
exit 1
fi
echo "passed: UDP port range"
# Test address with port range
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- "127.0.0.1:2000-2005"
' > conf/config.yaml
make init
if ! grep "listen 127.0.0.1:2000-2005" conf/nginx.conf > /dev/null; then
echo "failed: address with port range not found in nginx.conf"
exit 1
fi
echo "passed: address with port range"
# Test object form (table) with port range and TLS
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- addr: "5000-5005"
tls: true
' > conf/config.yaml
make init
if ! grep "listen 5000-5005.*ssl" conf/nginx.conf > /dev/null; then
echo "failed: object form port range with TLS not found"
exit 1
fi
echo "passed: object form port range with TLS"
# Test object form with address and port range
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- addr: "127.0.0.1:3000-3005"
tls: true
' > conf/config.yaml
make init
if ! grep "listen 127.0.0.1:3000-3005.*ssl" conf/nginx.conf > /dev/null; then
echo "failed: object form address with port range and TLS not found"
exit 1
fi
echo "passed: object form address with port range and TLS"
# Test mixed entries: ranges + individual ports + addresses coexist
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- 9100
- "127.0.0.1:9101"
- addr: 9102
tls: true
- "2000-2005"
- addr: "3000-3005"
udp:
- 9200
- "9300-9305"
' > conf/config.yaml
make init
if ! grep "listen 9100" conf/nginx.conf > /dev/null; then
echo "failed: individual port 9100 not found"
exit 1
fi
if ! grep "listen 127.0.0.1:9101" conf/nginx.conf > /dev/null; then
echo "failed: address port 127.0.0.1:9101 not found"
exit 1
fi
if ! grep "listen 9102.*ssl" conf/nginx.conf > /dev/null; then
echo "failed: TLS port 9102 not found"
exit 1
fi
if ! grep "listen 2000-2005" conf/nginx.conf > /dev/null; then
echo "failed: range 2000-2005 not found"
exit 1
fi
if ! grep "listen 3000-3005" conf/nginx.conf > /dev/null; then
echo "failed: table form range 3000-3005 not found"
exit 1
fi
if ! grep "listen 9200 udp" conf/nginx.conf > /dev/null; then
echo "failed: UDP port 9200 not found"
exit 1
fi
if ! grep "listen 9300-9305 udp" conf/nginx.conf > /dev/null; then
echo "failed: UDP range 9300-9305 not found"
exit 1
fi
echo "passed: mixed entries coexistence"
# Test backward compatibility: existing formats still work
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- addr: 9100
tls: true
- addr: "127.0.0.1:9101"
udp:
- 9200
- "127.0.0.1:9201"
' > conf/config.yaml
make init
if ! grep "listen 9100.*ssl" conf/nginx.conf > /dev/null; then
echo "failed: backward compat - TLS port 9100 not found"
exit 1
fi
if ! grep "listen 127.0.0.1:9101" conf/nginx.conf > /dev/null; then
echo "failed: backward compat - addr port not found"
exit 1
fi
if ! grep "listen 9200 udp" conf/nginx.conf > /dev/null; then
echo "failed: backward compat - UDP port 9200 not found"
exit 1
fi
if ! grep "listen 127.0.0.1:9201 udp" conf/nginx.conf > /dev/null; then
echo "failed: backward compat - UDP addr port not found"
exit 1
fi
echo "passed: backward compatibility"
# === Negative test cases: invalid ports/ranges should be rejected ===
# Invalid: port 0
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- 0
' > conf/config.yaml
out=$(make init 2>&1 || true)
if ! echo "$out" | grep "port out of range"; then
echo "failed: port 0 should be rejected"
exit 1
fi
echo "passed: reject port 0"
# Invalid: port 65536
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- 65536
' > conf/config.yaml
out=$(make init 2>&1 || true)
if ! echo "$out" | grep "port out of range"; then
echo "failed: port 65536 should be rejected"
exit 1
fi
echo "passed: reject port 65536"
# Invalid: float port (80.5 as YAML number — rejected by schema)
echo '
apisix:
stream_proxy:
tcp:
- 80.5
' > conf/config.yaml
out=$(make init 2>&1 || true)
if ! echo "$out" | grep "failed to validate"; then
echo "failed: float port 80.5 should be rejected"
exit 1
fi
echo "passed: reject float port 80.5"
# Invalid: reversed range (start > end)
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- "3000-2000"
' > conf/config.yaml
out=$(make init 2>&1 || true)
if ! echo "$out" | grep "invalid port range"; then
echo "failed: reversed range 3000-2000 should be rejected"
exit 1
fi
echo "passed: reject reversed range"
# Invalid: range with port 0
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- "0-100"
' > conf/config.yaml
out=$(make init 2>&1 || true)
if ! echo "$out" | grep "port out of range"; then
echo "failed: range starting at 0 should be rejected"
exit 1
fi
echo "passed: reject range with port 0"
# Invalid: range exceeding 65535
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- "100-70000"
' > conf/config.yaml
out=$(make init 2>&1 || true)
if ! echo "$out" | grep "port out of range"; then
echo "failed: range exceeding 65535 should be rejected"
exit 1
fi
echo "passed: reject range exceeding 65535"
# Invalid: addr with port out of range
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- "127.0.0.1:0"
' > conf/config.yaml
out=$(make init 2>&1 || true)
if ! echo "$out" | grep "port out of range"; then
echo "failed: addr with port 0 should be rejected"
exit 1
fi
echo "passed: reject addr with port 0"
# Invalid: addr with port exceeding 65535
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- "127.0.0.1:65536"
' > conf/config.yaml
out=$(make init 2>&1 || true)
if ! echo "$out" | grep "port out of range"; then
echo "failed: addr with port 65536 should be rejected"
exit 1
fi
echo "passed: reject addr with port 65536"
# Invalid: string "80.5" (float as string)
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- "80.5"
' > conf/config.yaml
out=$(make init 2>&1 || true)
if ! echo "$out" | grep "invalid port format"; then
echo "failed: string 80.5 should be rejected"
exit 1
fi
echo "passed: reject string 80.5"
# Invalid: string "1e3" (scientific notation as string)
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- "1e3"
' > conf/config.yaml
out=$(make init 2>&1 || true)
if ! echo "$out" | grep "invalid port format"; then
echo "failed: string 1e3 should be rejected"
exit 1
fi
echo "passed: reject string 1e3"
# Invalid: missing port "127.0.0.1:"
echo '
apisix:
proxy_mode: "http&stream"
stream_proxy:
tcp:
- "127.0.0.1:"
' > conf/config.yaml
out=$(make init 2>&1 || true)
if ! echo "$out" | grep "missing port"; then
echo "failed: missing port in 127.0.0.1: should be rejected"
exit 1
fi
echo "passed: reject missing port"
# Integration test: stream_route with port range (end-to-end traffic verification)
# Use nginx stream_configuration_snippet to create an inline upstream server
cat > conf/config.yaml << 'EOF'
apisix:
proxy_mode: "http&stream"
stream_proxy:
only: false
tcp:
- "9100-9102"
deployment:
admin:
admin_key:
- name: admin
key: test-port-range-key
role: admin
nginx_config:
stream_configuration_snippet: |
server {
listen 9201;
return "STREAM PORT RANGE OK\n";
}
EOF
make run
wait_for_tcp 127.0.0.1 9180
wait_for_tcp 127.0.0.1 9100
wait_for_tcp 127.0.0.1 9101
# Create a stream route targeting the inline upstream
curl -k -i http://127.0.0.1:9180/apisix/admin/stream_routes/1 \
-H 'X-API-KEY: test-port-range-key' -X PUT -d \
'{"upstream":{"nodes":{"127.0.0.1:9201":1},"type":"roundrobin"}}'
# Retry each port under a 10s deadline to cover etcd->stream-worker propagation.
for port in 9100 9101; do
ok=0
deadline=$(( $(date +%s) + 10 ))
{ set +x; } 2>/dev/null
while [ "$(date +%s)" -lt "$deadline" ]; do
if echo -e "" | nc -w 2 127.0.0.1 $port | grep -q "STREAM PORT RANGE OK"; then
ok=1
break
fi
sleep 0.3
done
set -x
if [ "$ok" -ne 1 ]; then
echo "failed: stream_route with port range - no response on port $port"
check_failure
exit 1
fi
done
make stop
echo "passed: stream_route with port range (end-to-end)"
echo "All stream port range tests passed."