Commit b50b21d3 authored by Mikio Hara's avatar Mikio Hara

net: make Dial, Listen{,Packet} for TCP/UDP with invalid port fail

This change makes Dial, Listen and ListenPacket with invalid port fail
whatever GODEBUG=netdns is.

Please be informed that cgoLookupPort with an out of range literal
number may return either the lower or upper bound value, 0 or 65535,
with no error on some platform.

Fixes #11715.

Change-Id: I43f9c4fb5526d1bf50b97698e0eb39d29fd74c35
Reviewed-on: https://go-review.googlesource.com/12447Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 3d5163cf
......@@ -116,8 +116,10 @@ var dialErrorTests = []struct {
{"tcp", "no-such-name:80"},
{"tcp", "mh/astro/r70:http"},
{"tcp", "127.0.0.1:0"},
{"udp", "127.0.0.1:0"},
{"tcp", JoinHostPort("127.0.0.1", "-1")},
{"tcp", JoinHostPort("127.0.0.1", "123456789")},
{"udp", JoinHostPort("127.0.0.1", "-1")},
{"udp", JoinHostPort("127.0.0.1", "123456789")},
{"ip:icmp", "127.0.0.1"},
{"unix", "/path/to/somewhere"},
......@@ -145,10 +147,23 @@ func TestDialError(t *testing.T) {
for i, tt := range dialErrorTests {
c, err := d.Dial(tt.network, tt.address)
if err == nil {
t.Errorf("#%d: should fail; %s:%s->%s", i, tt.network, c.LocalAddr(), c.RemoteAddr())
t.Errorf("#%d: should fail; %s:%s->%s", i, c.LocalAddr().Network(), c.LocalAddr(), c.RemoteAddr())
c.Close()
continue
}
if tt.network == "tcp" || tt.network == "udp" {
nerr := err
if op, ok := nerr.(*OpError); ok {
nerr = op.Err
}
if sys, ok := nerr.(*os.SyscallError); ok {
nerr = sys.Err
}
if nerr == errOpNotSupported {
t.Errorf("#%d: should fail without %v; %s:%s->", i, nerr, tt.network, tt.address)
continue
}
}
if c != nil {
t.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c, c)
}
......@@ -198,7 +213,8 @@ var listenErrorTests = []struct {
{"tcp", "no-such-name:80"},
{"tcp", "mh/astro/r70:http"},
{"tcp", "127.0.0.1:0"},
{"tcp", JoinHostPort("127.0.0.1", "-1")},
{"tcp", JoinHostPort("127.0.0.1", "123456789")},
{"unix", "/path/to/somewhere"},
{"unixpacket", "/path/to/somewhere"},
......@@ -223,10 +239,23 @@ func TestListenError(t *testing.T) {
for i, tt := range listenErrorTests {
ln, err := Listen(tt.network, tt.address)
if err == nil {
t.Errorf("#%d: should fail; %s:%s->", i, tt.network, ln.Addr())
t.Errorf("#%d: should fail; %s:%s->", i, ln.Addr().Network(), ln.Addr())
ln.Close()
continue
}
if tt.network == "tcp" {
nerr := err
if op, ok := nerr.(*OpError); ok {
nerr = op.Err
}
if sys, ok := nerr.(*os.SyscallError); ok {
nerr = sys.Err
}
if nerr == errOpNotSupported {
t.Errorf("#%d: should fail without %v; %s:%s->", i, nerr, tt.network, tt.address)
continue
}
}
if ln != nil {
t.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln, ln)
}
......@@ -246,6 +275,9 @@ var listenPacketErrorTests = []struct {
{"udp", "127.0.0.1:☺"},
{"udp", "no-such-name:80"},
{"udp", "mh/astro/r70:http"},
{"udp", JoinHostPort("127.0.0.1", "-1")},
{"udp", JoinHostPort("127.0.0.1", "123456789")},
}
func TestListenPacketError(t *testing.T) {
......@@ -263,7 +295,7 @@ func TestListenPacketError(t *testing.T) {
for i, tt := range listenPacketErrorTests {
c, err := ListenPacket(tt.network, tt.address)
if err == nil {
t.Errorf("#%d: should fail; %s:%s->", i, tt.network, c.LocalAddr())
t.Errorf("#%d: should fail; %s:%s->", i, c.LocalAddr().Network(), c.LocalAddr())
c.Close()
continue
}
......
......@@ -213,7 +213,7 @@ func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
if host, port, err = SplitHostPort(addr); err != nil {
return nil, err
}
if portnum, err = parsePort(net, port); err != nil {
if portnum, err = LookupPort(net, port); err != nil {
return nil, err
}
}
......
......@@ -123,10 +123,17 @@ func lookupIPDeadline(host string, deadline time.Time) (addrs []IPAddr, err erro
// LookupPort looks up the port for the given network and service.
func LookupPort(network, service string) (port int, err error) {
if n, i, ok := dtoi(service, 0); ok && i == len(service) {
return n, nil
port, _, ok := dtoi(service, 0)
if !ok && port != big && port != -big {
port, err = lookupPort(network, service)
if err != nil {
return 0, err
}
}
return lookupPort(network, service)
if 0 > port || port > 65535 {
return 0, &AddrError{Err: "invalid port", Addr: service}
}
return port, nil
}
// LookupCNAME returns the canonical DNS host for the given name.
......
......@@ -118,15 +118,27 @@ const big = 0xFFFFFF
// Returns number, new offset, success.
func dtoi(s string, i0 int) (n int, i int, ok bool) {
n = 0
neg := false
if len(s) > 0 && s[0] == '-' {
neg = true
s = s[1:]
}
for i = i0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
n = n*10 + int(s[i]-'0')
if n >= big {
return 0, i, false
if neg {
return -big, i + 1, false
}
return big, i, false
}
}
if i == i0 {
return 0, i, false
}
if neg {
n = -n
i++
}
return n, i, true
}
......
......@@ -77,3 +77,25 @@ func TestGoDebugString(t *testing.T) {
}
}
}
func TestDtoi(t *testing.T) {
for _, tt := range []struct {
in string
out int
off int
ok bool
}{
{"", 0, 0, false},
{"-123456789", -big, 9, false},
{"-1", -1, 2, true},
{"0", 0, 1, true},
{"65536", 65536, 5, true},
{"123456789", big, 8, false},
} {
n, i, ok := dtoi(tt.in, 0)
if n != tt.out || i != tt.off || ok != tt.ok {
t.Errorf("got %d, %d, %v; want %d, %d, %v", n, i, ok, tt.out, tt.off, tt.ok)
}
}
}
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Network service port manipulations
package net
// parsePort parses port as a network service port number for both
// TCP and UDP.
func parsePort(net, port string) (int, error) {
p, i, ok := dtoi(port, 0)
if !ok || i != len(port) {
var err error
p, err = LookupPort(net, port)
if err != nil {
return 0, err
}
}
if p < 0 || p > 0xFFFF {
return 0, &AddrError{Err: "invalid port", Addr: port}
}
return p, nil
}
......@@ -9,12 +9,13 @@ import (
"testing"
)
var portTests = []struct {
var lookupPortTests = []struct {
network string
name string
port int
ok bool
}{
{"tcp", "0", 0, true},
{"tcp", "echo", 7, true},
{"tcp", "discard", 9, true},
{"tcp", "systat", 11, true},
......@@ -29,6 +30,7 @@ var portTests = []struct {
{"tcp", "finger", 79, true},
{"tcp", "42", 42, true},
{"udp", "0", 0, true},
{"udp", "echo", 7, true},
{"udp", "tftp", 69, true},
{"udp", "bootpc", 68, true},
......@@ -41,6 +43,10 @@ var portTests = []struct {
{"--badnet--", "zzz", 0, false},
{"tcp", "--badport--", 0, false},
{"tcp", "-1", 0, false},
{"tcp", "65536", 0, false},
{"udp", "-1", 0, false},
{"udp", "65536", 0, false},
}
func TestLookupPort(t *testing.T) {
......@@ -49,9 +55,9 @@ func TestLookupPort(t *testing.T) {
t.Skipf("not supported on %s", runtime.GOOS)
}
for _, tt := range portTests {
for _, tt := range lookupPortTests {
if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok {
t.Errorf("LookupPort(%q, %q) = %v, %v; want %v", tt.network, tt.name, port, err, tt.port)
t.Errorf("LookupPort(%q, %q) = %d, %v; want %d", tt.network, tt.name, port, err, tt.port)
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment