1
0
mirror of https://github.com/golang/go synced 2024-11-24 02:50:11 -07:00

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/12447
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Mikio Hara 2015-07-21 12:51:01 +09:00
parent 3d5163cf43
commit b50b21d3e1
7 changed files with 93 additions and 38 deletions

View File

@ -116,8 +116,10 @@ var dialErrorTests = []struct {
{"tcp", "no-such-name:80"}, {"tcp", "no-such-name:80"},
{"tcp", "mh/astro/r70:http"}, {"tcp", "mh/astro/r70:http"},
{"tcp", "127.0.0.1:0"}, {"tcp", JoinHostPort("127.0.0.1", "-1")},
{"udp", "127.0.0.1:0"}, {"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"}, {"ip:icmp", "127.0.0.1"},
{"unix", "/path/to/somewhere"}, {"unix", "/path/to/somewhere"},
@ -145,10 +147,23 @@ func TestDialError(t *testing.T) {
for i, tt := range dialErrorTests { for i, tt := range dialErrorTests {
c, err := d.Dial(tt.network, tt.address) c, err := d.Dial(tt.network, tt.address)
if err == nil { 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() c.Close()
continue 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 { if c != nil {
t.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c, c) 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", "no-such-name:80"},
{"tcp", "mh/astro/r70:http"}, {"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"}, {"unix", "/path/to/somewhere"},
{"unixpacket", "/path/to/somewhere"}, {"unixpacket", "/path/to/somewhere"},
@ -223,10 +239,23 @@ func TestListenError(t *testing.T) {
for i, tt := range listenErrorTests { for i, tt := range listenErrorTests {
ln, err := Listen(tt.network, tt.address) ln, err := Listen(tt.network, tt.address)
if err == nil { 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() ln.Close()
continue 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 { if ln != nil {
t.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln, ln) 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", "127.0.0.1:☺"},
{"udp", "no-such-name:80"}, {"udp", "no-such-name:80"},
{"udp", "mh/astro/r70:http"}, {"udp", "mh/astro/r70:http"},
{"udp", JoinHostPort("127.0.0.1", "-1")},
{"udp", JoinHostPort("127.0.0.1", "123456789")},
} }
func TestListenPacketError(t *testing.T) { func TestListenPacketError(t *testing.T) {
@ -263,7 +295,7 @@ func TestListenPacketError(t *testing.T) {
for i, tt := range listenPacketErrorTests { for i, tt := range listenPacketErrorTests {
c, err := ListenPacket(tt.network, tt.address) c, err := ListenPacket(tt.network, tt.address)
if err == nil { 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() c.Close()
continue continue
} }

View File

@ -213,7 +213,7 @@ func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
if host, port, err = SplitHostPort(addr); err != nil { if host, port, err = SplitHostPort(addr); err != nil {
return nil, err return nil, err
} }
if portnum, err = parsePort(net, port); err != nil { if portnum, err = LookupPort(net, port); err != nil {
return nil, err return nil, err
} }
} }

View File

@ -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. // LookupPort looks up the port for the given network and service.
func LookupPort(network, service string) (port int, err error) { func LookupPort(network, service string) (port int, err error) {
if n, i, ok := dtoi(service, 0); ok && i == len(service) { port, _, ok := dtoi(service, 0)
return n, nil 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. // LookupCNAME returns the canonical DNS host for the given name.

View File

@ -118,15 +118,27 @@ const big = 0xFFFFFF
// Returns number, new offset, success. // Returns number, new offset, success.
func dtoi(s string, i0 int) (n int, i int, ok bool) { func dtoi(s string, i0 int) (n int, i int, ok bool) {
n = 0 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++ { for i = i0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
n = n*10 + int(s[i]-'0') n = n*10 + int(s[i]-'0')
if n >= big { if n >= big {
return 0, i, false if neg {
return -big, i + 1, false
}
return big, i, false
} }
} }
if i == i0 { if i == i0 {
return 0, i, false return 0, i, false
} }
if neg {
n = -n
i++
}
return n, i, true return n, i, true
} }

View File

@ -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)
}
}
}

View File

@ -1,24 +0,0 @@
// 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
}

View File

@ -9,12 +9,13 @@ import (
"testing" "testing"
) )
var portTests = []struct { var lookupPortTests = []struct {
network string network string
name string name string
port int port int
ok bool ok bool
}{ }{
{"tcp", "0", 0, true},
{"tcp", "echo", 7, true}, {"tcp", "echo", 7, true},
{"tcp", "discard", 9, true}, {"tcp", "discard", 9, true},
{"tcp", "systat", 11, true}, {"tcp", "systat", 11, true},
@ -29,6 +30,7 @@ var portTests = []struct {
{"tcp", "finger", 79, true}, {"tcp", "finger", 79, true},
{"tcp", "42", 42, true}, {"tcp", "42", 42, true},
{"udp", "0", 0, true},
{"udp", "echo", 7, true}, {"udp", "echo", 7, true},
{"udp", "tftp", 69, true}, {"udp", "tftp", 69, true},
{"udp", "bootpc", 68, true}, {"udp", "bootpc", 68, true},
@ -41,6 +43,10 @@ var portTests = []struct {
{"--badnet--", "zzz", 0, false}, {"--badnet--", "zzz", 0, false},
{"tcp", "--badport--", 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) { func TestLookupPort(t *testing.T) {
@ -49,9 +55,9 @@ func TestLookupPort(t *testing.T) {
t.Skipf("not supported on %s", runtime.GOOS) 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 { 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)
} }
} }
} }