{"action":"created","issue":{"url":"https://api.github.com/repos/golang/go/issues/25104","repository_url":"https://api.github.com/repos/golang/go","labels_url":"https://api.github.com/repos/golang/go/issues/25104/labels{/name}","comments_url":"https://api.github.com/repos/golang/go/issues/25104/comments","events_url":"https://api.github.com/repos/golang/go/issues/25104/events","html_url":"https://github.com/golang/go/issues/25104","id":318019333,"number":25104,"title":"x/net/proxy: socks5 dialer results can no longer be cast to *net.TCPConn","user":{"login":"rhs","id":70215,"avatar_url":"https://avatars3.githubusercontent.com/u/70215?v=4","gravatar_id":"","url":"https://api.github.com/users/rhs","html_url":"https://github.com/rhs","followers_url":"https://api.github.com/users/rhs/followers","following_url":"https://api.github.com/users/rhs/following{/other_user}","gists_url":"https://api.github.com/users/rhs/gists{/gist_id}","starred_url":"https://api.github.com/users/rhs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rhs/subscriptions","organizations_url":"https://api.github.com/users/rhs/orgs","repos_url":"https://api.github.com/users/rhs/repos","events_url":"https://api.github.com/users/rhs/events{/privacy}","received_events_url":"https://api.github.com/users/rhs/received_events","type":"User","site_admin":false},"labels":[{"id":373402289,"url":"https://api.github.com/repos/golang/go/labels/NeedsInvestigation","name":"NeedsInvestigation","color":"ededed","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2018-04-26T13:00:42Z","updated_at":"2018-04-27T08:08:42Z","closed_at":null,"author_association":"NONE","body":"Something recent (it appears to be this commit: https://github.com/golang/net/commit/61147c48b25b599e5b561d2e9c4f3e1ef489ca41#diff-431387eb7262e1cfc79b125eb8a67c60) has broken the cast to *net.TCPConn. I don't know if this is intentional or not. If it is then I'd appreciate any advice on how to accomplish what I'm trying to do without the cast.\r\n\r\n### What version of Go are you using (`go version`)?\r\n\r\ngo version go1.10.1 linux/amd64\r\n\r\n### Does this issue reproduce with the latest release?\r\n\r\nYes\r\n\r\n### What operating system and processor architecture are you using (`go env`)?\r\n\r\nGOARCH=\"amd64\"\r\nGOBIN=\"\"\r\nGOCACHE=\"/home/rhs/.cache/go-build\"\r\nGOEXE=\"\"\r\nGOHOSTARCH=\"amd64\"\r\nGOHOSTOS=\"linux\"\r\nGOOS=\"linux\"\r\nGOPATH=\"/home/rhs/go\"\r\nGORACE=\"\"\r\nGOROOT=\"/usr/local/go\"\r\nGOTMPDIR=\"\"\r\nGOTOOLDIR=\"/usr/local/go/pkg/tool/linux_amd64\"\r\nGCCGO=\"gccgo\"\r\nCC=\"gcc\"\r\nCXX=\"g++\"\r\nCGO_ENABLED=\"1\"\r\nCGO_CFLAGS=\"-g -O2\"\r\nCGO_CPPFLAGS=\"\"\r\nCGO_CXXFLAGS=\"-g -O2\"\r\nCGO_FFLAGS=\"-g -O2\"\r\nCGO_LDFLAGS=\"-g -O2\"\r\nPKG_CONFIG=\"pkg-config\"\r\nGOGCCFLAGS=\"-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build051890453=/tmp/go-build -gno-record-gcc-switches\"\r\n\r\n### What did you do?\r\n\r\nThis is slightly complicated to setup, so bear with me here. The reproducer program is available here: https://gist.github.com/rhs/7ed17d49dff7196c3539d2d1b01f6049\r\n\r\n```\r\n# the ssh will eat a terminal\r\nssh -D localhost:1080 -C -N -oExitOnForwardFailure=yes <host-you-have-ssh-access-to>\r\n\r\ncurl -o repro.go https://gist.githubusercontent.com/rhs/7ed17d49dff7196c3539d2d1b01f6049/raw/bacb83282856af91dc496b2864d0559c86371284/repro.go\r\n# the go run will eat a terminal\r\ngo run repro.go\r\n\r\ncurl localhost:1234\r\n```\r\n\r\n### What did you expect to see?\r\n\r\nUntil recently this worked fine and connections were proxied:\r\n\r\n```html\r\ncurl localhost:1234\r\n<!DOCTYPE html>\r\n\t<html>\r\n\t  <head>\r\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\r\n\t\t<meta charset=\"utf-8\">\r\n\t\t<title>No such app</title>\r\n\t\t<style media=\"screen\">\r\n\t\t  html,body,iframe {\r\n\t\t\tmargin: 0;\r\n\t\t\tpadding: 0;\r\n\t\t  }\r\n\t\t  html,body {\r\n\t\t\theight: 100%;\r\n\t\t\toverflow: hidden;\r\n\t\t  }\r\n\t\t  iframe {\r\n\t\t\twidth: 100%;\r\n\t\t\theight: 100%;\r\n\t\t\tborder: 0;\r\n\t\t  }\r\n\t\t</style>\r\n\t  </head>\r\n\t  <body>\r\n\t\t<iframe src=\"//www.herokucdn.com/error-pages/no-such-app.html\"></iframe>\r\n\t  </body>\r\n\t</html>\r\n```\r\n\r\n### What did you see instead?\r\n\r\nNow the cast fails with a panic:\r\n\r\n```\r\ngo run repro.go \r\n2018/04/26 08:34:59 Listening...\r\n2018/04/26 08:35:03 CONNECTING: [::1]:45440 to 0xc4200102f0\r\npanic: interface conversion: net.Conn is *socks.Conn, not *net.TCPConn\r\n\r\ngoroutine 5 [running]:\r\nmain.handleConnection(0xc42000e040)\r\n\t/home/rhs/repro.go:54 +0x2fa\r\ncreated by main.main\r\n\t/home/rhs/repro.go:30 +0x16b\r\nexit status 2\r\n```"},"comment":{"url":"https://api.github.com/repos/golang/go/issues/comments/384897962","html_url":"https://github.com/golang/go/issues/25104#issuecomment-384897962","issue_url":"https://api.github.com/repos/golang/go/issues/25104","id":384897962,"user":{"login":"mikioh","id":92117,"avatar_url":"https://avatars1.githubusercontent.com/u/92117?v=4","gravatar_id":"","url":"https://api.github.com/users/mikioh","html_url":"https://github.com/mikioh","followers_url":"https://api.github.com/users/mikioh/followers","following_url":"https://api.github.com/users/mikioh/following{/other_user}","gists_url":"https://api.github.com/users/mikioh/gists{/gist_id}","starred_url":"https://api.github.com/users/mikioh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mikioh/subscriptions","organizations_url":"https://api.github.com/users/mikioh/orgs","repos_url":"https://api.github.com/users/mikioh/repos","events_url":"https://api.github.com/users/mikioh/events{/privacy}","received_events_url":"https://api.github.com/users/mikioh/received_events","type":"User","site_admin":false},"created_at":"2018-04-27T08:08:42Z","updated_at":"2018-04-27T08:08:42Z","author_association":"CONTRIBUTOR","body":"> I don't know if this is intentional or not.\r\n\r\nThere's no guarantee that the returned interface always contains a specific concrete type, as the package description says that \"for a variety of protocols.\" Otherwise, we cannot implement a bit complicated stuff like SOCKSv6 over TLS 1.3 in near future.\r\n\r\n> how to accomplish what I'm trying to do without the cast.\r\n\r\nA simple way would be using the 4th parameter of the SOCKS5 function like the following:\r\n```\r\ntype sled struct { // or sledge\r\n        tls *tls.Conn\r\n        tcp *net.TCPConn\r\n        udp *net.UDPConn\r\n}\r\n\r\nfunc (s *sled) Dial(network, address string) (net.Conn, error) { // satisfies proxy.Dialer interface\r\n        switch network {\r\n        case \"tcp\", \"tcp4\", \"tcp6\":\r\n                c, err := net.Dial(network, address)\r\n                if err != nil {\r\n                        return nil, err\r\n                }\r\n                s.tcp = c.(*net.TCPConn)\r\n                return c, nil\r\n        }\r\n        return nil, errors.New(\"not implemented yet\")\r\n}\r\n\r\nvar s sled\r\nd, err := proxy.SOCKS5(\"tcp\", \"somewhere:1080\", nil, &s)\r\nif err != nil {\r\n        // error handling\r\n}\r\n_, err = d.Dial(...)\r\nif err != nil {\r\n        // error handling\r\n}\r\n// Now you may use s.tcp safely.\r\n```\r\nPS: s/cast/type assertion/; the notation x.(T) is called a type assertion in the language specification. See https://golang.org/ref/spec#Type_assertions"}}
{"actor":{"display_login":"mikioh"}}