Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
whqwjb
go-ethereum
提交
cf4faa49
G
go-ethereum
项目概览
whqwjb
/
go-ethereum
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
go-ethereum
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
cf4faa49
编写于
5月 03, 2017
作者:
P
Péter Szilágyi
提交者:
Felix Lange
5月 03, 2017
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
cmd/puppeth, vendor: update ssh, manage server keys (#14398)
上级
59966255
变更
19
隐藏空白更改
内联
并排
Showing
19 changed file
with
701 addition
and
285 deletion
+701
-285
cmd/puppeth/ssh.go
cmd/puppeth/ssh.go
+44
-5
cmd/puppeth/wizard.go
cmd/puppeth/wizard.go
+12
-2
cmd/puppeth/wizard_intro.go
cmd/puppeth/wizard_intro.go
+6
-3
cmd/puppeth/wizard_netstats.go
cmd/puppeth/wizard_netstats.go
+2
-2
cmd/puppeth/wizard_network.go
cmd/puppeth/wizard_network.go
+11
-7
vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
+54
-77
vendor/golang.org/x/crypto/curve25519/curve25519.go
vendor/golang.org/x/crypto/curve25519/curve25519.go
+8
-15
vendor/golang.org/x/crypto/ssh/certs.go
vendor/golang.org/x/crypto/ssh/certs.go
+1
-1
vendor/golang.org/x/crypto/ssh/client.go
vendor/golang.org/x/crypto/ssh/client.go
+51
-5
vendor/golang.org/x/crypto/ssh/client_auth.go
vendor/golang.org/x/crypto/ssh/client_auth.go
+28
-17
vendor/golang.org/x/crypto/ssh/common.go
vendor/golang.org/x/crypto/ssh/common.go
+8
-6
vendor/golang.org/x/crypto/ssh/doc.go
vendor/golang.org/x/crypto/ssh/doc.go
+3
-0
vendor/golang.org/x/crypto/ssh/handshake.go
vendor/golang.org/x/crypto/ssh/handshake.go
+34
-19
vendor/golang.org/x/crypto/ssh/keys.go
vendor/golang.org/x/crypto/ssh/keys.go
+71
-19
vendor/golang.org/x/crypto/ssh/server.go
vendor/golang.org/x/crypto/ssh/server.go
+33
-0
vendor/golang.org/x/crypto/ssh/streamlocal.go
vendor/golang.org/x/crypto/ssh/streamlocal.go
+115
-0
vendor/golang.org/x/crypto/ssh/tcpip.go
vendor/golang.org/x/crypto/ssh/tcpip.go
+128
-70
vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
+59
-4
vendor/vendor.json
vendor/vendor.json
+33
-33
未找到文件。
cmd/puppeth/ssh.go
浏览文件 @
cf4faa49
...
...
@@ -17,6 +17,8 @@
package
main
import
(
"bufio"
"bytes"
"errors"
"fmt"
"io/ioutil"
...
...
@@ -37,18 +39,26 @@ import (
type
sshClient
struct
{
server
string
// Server name or IP without port number
address
string
// IP address of the remote server
pubkey
[]
byte
// RSA public key to authenticate the server
client
*
ssh
.
Client
logger
log
.
Logger
}
// dial establishes an SSH connection to a remote node using the current user and
// the user's configured private RSA key.
func
dial
(
server
string
)
(
*
sshClient
,
error
)
{
// the user's configured private RSA key. If that fails, password authentication
// is fallen back to. The caller may override the login user via user@server:port.
func
dial
(
server
string
,
pubkey
[]
byte
)
(
*
sshClient
,
error
)
{
// Figure out a label for the server and a logger
label
:=
server
if
strings
.
Contains
(
label
,
":"
)
{
label
=
label
[
:
strings
.
Index
(
label
,
":"
)]
}
login
:=
""
if
strings
.
Contains
(
server
,
"@"
)
{
login
=
label
[
:
strings
.
Index
(
label
,
"@"
)]
label
=
label
[
strings
.
Index
(
label
,
"@"
)
+
1
:
]
server
=
server
[
strings
.
Index
(
server
,
"@"
)
+
1
:
]
}
logger
:=
log
.
New
(
"server"
,
label
)
logger
.
Debug
(
"Attempting to establish SSH connection"
)
...
...
@@ -56,6 +66,9 @@ func dial(server string) (*sshClient, error) {
if
err
!=
nil
{
return
nil
,
err
}
if
login
==
""
{
login
=
user
.
Username
}
// Configure the supported authentication methods (private key and password)
var
auths
[]
ssh
.
AuthMethod
...
...
@@ -71,7 +84,7 @@ func dial(server string) (*sshClient, error) {
}
}
auths
=
append
(
auths
,
ssh
.
PasswordCallback
(
func
()
(
string
,
error
)
{
fmt
.
Printf
(
"What's the login password for %s at %s? (won't be echoed)
\n
> "
,
user
.
Username
,
server
)
fmt
.
Printf
(
"What's the login password for %s at %s? (won't be echoed)
\n
> "
,
login
,
server
)
blob
,
err
:=
terminal
.
ReadPassword
(
int
(
syscall
.
Stdin
))
fmt
.
Println
()
...
...
@@ -86,11 +99,36 @@ func dial(server string) (*sshClient, error) {
return
nil
,
errors
.
New
(
"no IPs associated with domain"
)
}
// Try to dial in to the remote server
logger
.
Trace
(
"Dialing remote SSH server"
,
"user"
,
user
.
Username
,
"key"
,
path
)
logger
.
Trace
(
"Dialing remote SSH server"
,
"user"
,
login
)
if
!
strings
.
Contains
(
server
,
":"
)
{
server
+=
":22"
}
client
,
err
:=
ssh
.
Dial
(
"tcp"
,
server
,
&
ssh
.
ClientConfig
{
User
:
user
.
Username
,
Auth
:
auths
})
keycheck
:=
func
(
hostname
string
,
remote
net
.
Addr
,
key
ssh
.
PublicKey
)
error
{
// If no public key is known for SSH, ask the user to confirm
if
pubkey
==
nil
{
fmt
.
Printf
(
"The authenticity of host '%s (%s)' can't be established.
\n
"
,
hostname
,
remote
)
fmt
.
Printf
(
"SSH key fingerprint is %s [MD5]
\n
"
,
ssh
.
FingerprintLegacyMD5
(
key
))
fmt
.
Printf
(
"Are you sure you want to continue connecting (yes/no)? "
)
text
,
err
:=
bufio
.
NewReader
(
os
.
Stdin
)
.
ReadString
(
'\n'
)
switch
{
case
err
!=
nil
:
return
err
case
strings
.
TrimSpace
(
text
)
==
"yes"
:
pubkey
=
key
.
Marshal
()
return
nil
default
:
return
fmt
.
Errorf
(
"unknown auth choice: %v"
,
text
)
}
}
// If a public key exists for this SSH server, check that it matches
if
bytes
.
Compare
(
pubkey
,
key
.
Marshal
())
==
0
{
return
nil
}
// We have a mismatch, forbid connecting
return
errors
.
New
(
"ssh key mismatch, readd the machine to update"
)
}
client
,
err
:=
ssh
.
Dial
(
"tcp"
,
server
,
&
ssh
.
ClientConfig
{
User
:
login
,
Auth
:
auths
,
HostKeyCallback
:
keycheck
})
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -98,6 +136,7 @@ func dial(server string) (*sshClient, error) {
c
:=
&
sshClient
{
server
:
label
,
address
:
addr
[
0
],
pubkey
:
pubkey
,
client
:
client
,
logger
:
logger
,
}
...
...
cmd/puppeth/wizard.go
浏览文件 @
cf4faa49
...
...
@@ -44,14 +44,24 @@ type config struct {
bootLight
[]
string
// Bootnodes to always connect to by light nodes
ethstats
string
// Ethstats settings to cache for node deploys
Servers
[]
string
`json:"servers,omitempty"`
Servers
map
[
string
][]
byte
`json:"servers,omitempty"`
}
// servers retrieves an alphabetically sorted list of servers.
func
(
c
config
)
servers
()
[]
string
{
servers
:=
make
([]
string
,
0
,
len
(
c
.
Servers
))
for
server
:=
range
c
.
Servers
{
servers
=
append
(
servers
,
server
)
}
sort
.
Strings
(
servers
)
return
servers
}
// flush dumps the contents of config to disk.
func
(
c
config
)
flush
()
{
os
.
MkdirAll
(
filepath
.
Dir
(
c
.
path
),
0755
)
sort
.
Strings
(
c
.
Servers
)
out
,
_
:=
json
.
MarshalIndent
(
c
,
""
,
" "
)
if
err
:=
ioutil
.
WriteFile
(
c
.
path
,
out
,
0644
);
err
!=
nil
{
log
.
Warn
(
"Failed to save puppeth configs"
,
"file"
,
c
.
path
,
"err"
,
err
)
...
...
cmd/puppeth/wizard_intro.go
浏览文件 @
cf4faa49
...
...
@@ -31,7 +31,10 @@ import (
// makeWizard creates and returns a new puppeth wizard.
func
makeWizard
(
network
string
)
*
wizard
{
return
&
wizard
{
network
:
network
,
network
:
network
,
conf
:
config
{
Servers
:
make
(
map
[
string
][]
byte
),
},
servers
:
make
(
map
[
string
]
*
sshClient
),
services
:
make
(
map
[
string
][]
string
),
in
:
bufio
.
NewReader
(
os
.
Stdin
),
...
...
@@ -77,9 +80,9 @@ func (w *wizard) run() {
}
else
if
err
:=
json
.
Unmarshal
(
blob
,
&
w
.
conf
);
err
!=
nil
{
log
.
Crit
(
"Previous configuration corrupted"
,
"path"
,
w
.
conf
.
path
,
"err"
,
err
)
}
else
{
for
_
,
server
:=
range
w
.
conf
.
Servers
{
for
server
,
pubkey
:=
range
w
.
conf
.
Servers
{
log
.
Info
(
"Dialing previously configured server"
,
"server"
,
server
)
client
,
err
:=
dial
(
server
)
client
,
err
:=
dial
(
server
,
pubkey
)
if
err
!=
nil
{
log
.
Error
(
"Previous server unreachable"
,
"server"
,
server
,
"err"
,
err
)
}
...
...
cmd/puppeth/wizard_netstats.go
浏览文件 @
cf4faa49
...
...
@@ -41,14 +41,14 @@ func (w *wizard) networkStats(tips bool) {
stats
.
SetHeader
([]
string
{
"Server"
,
"IP"
,
"Status"
,
"Service"
,
"Details"
})
stats
.
SetColWidth
(
128
)
for
_
,
server
:=
range
w
.
conf
.
Servers
{
for
server
,
pubkey
:=
range
w
.
conf
.
Servers
{
client
:=
w
.
servers
[
server
]
logger
:=
log
.
New
(
"server"
,
server
)
logger
.
Info
(
"Starting remote server health-check"
)
// If the server is not connected, try to connect again
if
client
==
nil
{
conn
,
err
:=
dial
(
server
)
conn
,
err
:=
dial
(
server
,
pubkey
)
if
err
!=
nil
{
logger
.
Error
(
"Failed to establish remote connection"
,
"err"
,
err
)
stats
.
Append
([]
string
{
server
,
""
,
err
.
Error
(),
""
,
""
})
...
...
cmd/puppeth/wizard_network.go
浏览文件 @
cf4faa49
...
...
@@ -28,7 +28,9 @@ import (
func
(
w
*
wizard
)
manageServers
()
{
// List all the servers we can disconnect, along with an entry to connect a new one
fmt
.
Println
()
for
i
,
server
:=
range
w
.
conf
.
Servers
{
servers
:=
w
.
conf
.
servers
()
for
i
,
server
:=
range
servers
{
fmt
.
Printf
(
" %d. Disconnect %s
\n
"
,
i
+
1
,
server
)
}
fmt
.
Printf
(
" %d. Connect another server
\n
"
,
len
(
w
.
conf
.
Servers
)
+
1
)
...
...
@@ -40,14 +42,14 @@ func (w *wizard) manageServers() {
}
// If the user selected an existing server, drop it
if
choice
<=
len
(
w
.
conf
.
Servers
)
{
server
:=
w
.
conf
.
S
ervers
[
choice
-
1
]
server
:=
s
ervers
[
choice
-
1
]
client
:=
w
.
servers
[
server
]
delete
(
w
.
servers
,
server
)
if
client
!=
nil
{
client
.
Close
()
}
w
.
conf
.
Servers
=
append
(
w
.
conf
.
Servers
[
:
choice
-
1
],
w
.
conf
.
Servers
[
choice
:
]
...
)
delete
(
w
.
conf
.
Servers
,
server
)
w
.
conf
.
flush
()
log
.
Info
(
"Disconnected existing server"
,
"server"
,
server
)
...
...
@@ -73,14 +75,14 @@ func (w *wizard) makeServer() string {
// Read and fial the server to ensure docker is present
input
:=
w
.
readString
()
client
,
err
:=
dial
(
input
)
client
,
err
:=
dial
(
input
,
nil
)
if
err
!=
nil
{
log
.
Error
(
"Server not ready for puppeth"
,
"err"
,
err
)
return
""
}
// All checks passed, start tracking the server
w
.
servers
[
input
]
=
client
w
.
conf
.
Servers
=
append
(
w
.
conf
.
Servers
,
input
)
w
.
conf
.
Servers
[
input
]
=
client
.
pubkey
w
.
conf
.
flush
()
return
input
...
...
@@ -93,7 +95,9 @@ func (w *wizard) selectServer() string {
// List the available server to the user and wait for a choice
fmt
.
Println
()
fmt
.
Println
(
"Which server do you want to interact with?"
)
for
i
,
server
:=
range
w
.
conf
.
Servers
{
servers
:=
w
.
conf
.
servers
()
for
i
,
server
:=
range
servers
{
fmt
.
Printf
(
" %d. %s
\n
"
,
i
+
1
,
server
)
}
fmt
.
Printf
(
" %d. Connect another server
\n
"
,
len
(
w
.
conf
.
Servers
)
+
1
)
...
...
@@ -105,7 +109,7 @@ func (w *wizard) selectServer() string {
}
// If the user requested connecting to a new server, go for it
if
choice
<=
len
(
w
.
conf
.
Servers
)
{
return
w
.
conf
.
S
ervers
[
choice
-
1
]
return
s
ervers
[
choice
-
1
]
}
return
w
.
makeServer
()
}
...
...
vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
浏览文件 @
cf4faa49
...
...
@@ -2,87 +2,64 @@
//
Use
of
this
source
code
is
governed
by
a
BSD
-
style
//
license
that
can
be
found
in
the
LICENSE
file
.
//
This
code
was
translated
into
a
form
compatible
with
6
a
from
the
public
//
domain
sources
in
SUPERCOP
:
http
:
//
bench
.
cr
.
yp
.
to
/
supercop
.
html
//
+
build
amd64
,!
gccgo
,!
appengine
//
func
cswap
(
inout
*[
5
]
uint64
,
v
uint64
)
//
func
cswap
(
inout
*[
4
][
5
]
uint64
,
v
uint64
)
TEXT
·
cswap
(
SB
),7,$0
MOVQ
inout
+
0
(
FP
),
DI
MOVQ
v
+
8
(
FP
),
SI
CMPQ
SI
,
$
1
MOVQ
0
(
DI
),
SI
MOVQ
80
(
DI
),
DX
MOVQ
8
(
DI
),
CX
MOVQ
88
(
DI
),
R8
MOVQ
SI
,
R9
CMOVQEQ
DX
,
SI
CMOVQEQ
R9
,
DX
MOVQ
CX
,
R9
CMOVQEQ
R8
,
CX
CMOVQEQ
R9
,
R8
MOVQ
SI
,
0
(
DI
)
MOVQ
DX
,
80
(
DI
)
MOVQ
CX
,
8
(
DI
)
MOVQ
R8
,
88
(
DI
)
MOVQ
16
(
DI
),
SI
MOVQ
96
(
DI
),
DX
MOVQ
24
(
DI
),
CX
MOVQ
104
(
DI
),
R8
MOVQ
SI
,
R9
CMOVQEQ
DX
,
SI
CMOVQEQ
R9
,
DX
MOVQ
CX
,
R9
CMOVQEQ
R8
,
CX
CMOVQEQ
R9
,
R8
MOVQ
SI
,
16
(
DI
)
MOVQ
DX
,
96
(
DI
)
MOVQ
CX
,
24
(
DI
)
MOVQ
R8
,
104
(
DI
)
MOVQ
32
(
DI
),
SI
MOVQ
112
(
DI
),
DX
MOVQ
40
(
DI
),
CX
MOVQ
120
(
DI
),
R8
MOVQ
SI
,
R9
CMOVQEQ
DX
,
SI
CMOVQEQ
R9
,
DX
MOVQ
CX
,
R9
CMOVQEQ
R8
,
CX
CMOVQEQ
R9
,
R8
MOVQ
SI
,
32
(
DI
)
MOVQ
DX
,
112
(
DI
)
MOVQ
CX
,
40
(
DI
)
MOVQ
R8
,
120
(
DI
)
MOVQ
48
(
DI
),
SI
MOVQ
128
(
DI
),
DX
MOVQ
56
(
DI
),
CX
MOVQ
136
(
DI
),
R8
MOVQ
SI
,
R9
CMOVQEQ
DX
,
SI
CMOVQEQ
R9
,
DX
MOVQ
CX
,
R9
CMOVQEQ
R8
,
CX
CMOVQEQ
R9
,
R8
MOVQ
SI
,
48
(
DI
)
MOVQ
DX
,
128
(
DI
)
MOVQ
CX
,
56
(
DI
)
MOVQ
R8
,
136
(
DI
)
MOVQ
64
(
DI
),
SI
MOVQ
144
(
DI
),
DX
MOVQ
72
(
DI
),
CX
MOVQ
152
(
DI
),
R8
MOVQ
SI
,
R9
CMOVQEQ
DX
,
SI
CMOVQEQ
R9
,
DX
MOVQ
CX
,
R9
CMOVQEQ
R8
,
CX
CMOVQEQ
R9
,
R8
MOVQ
SI
,
64
(
DI
)
MOVQ
DX
,
144
(
DI
)
MOVQ
CX
,
72
(
DI
)
MOVQ
R8
,
152
(
DI
)
MOVQ
DI
,
AX
MOVQ
SI
,
DX
SUBQ
$
1
,
SI
NOTQ
SI
MOVQ
SI
,
X15
PSHUFD
$
0x44
,
X15
,
X15
MOVOU
0
(
DI
),
X0
MOVOU
16
(
DI
),
X2
MOVOU
32
(
DI
),
X4
MOVOU
48
(
DI
),
X6
MOVOU
64
(
DI
),
X8
MOVOU
80
(
DI
),
X1
MOVOU
96
(
DI
),
X3
MOVOU
112
(
DI
),
X5
MOVOU
128
(
DI
),
X7
MOVOU
144
(
DI
),
X9
MOVO
X1
,
X10
MOVO
X3
,
X11
MOVO
X5
,
X12
MOVO
X7
,
X13
MOVO
X9
,
X14
PXOR
X0
,
X10
PXOR
X2
,
X11
PXOR
X4
,
X12
PXOR
X6
,
X13
PXOR
X8
,
X14
PAND
X15
,
X10
PAND
X15
,
X11
PAND
X15
,
X12
PAND
X15
,
X13
PAND
X15
,
X14
PXOR
X10
,
X0
PXOR
X10
,
X1
PXOR
X11
,
X2
PXOR
X11
,
X3
PXOR
X12
,
X4
PXOR
X12
,
X5
PXOR
X13
,
X6
PXOR
X13
,
X7
PXOR
X14
,
X8
PXOR
X14
,
X9
MOVOU
X0
,
0
(
DI
)
MOVOU
X2
,
16
(
DI
)
MOVOU
X4
,
32
(
DI
)
MOVOU
X6
,
48
(
DI
)
MOVOU
X8
,
64
(
DI
)
MOVOU
X1
,
80
(
DI
)
MOVOU
X3
,
96
(
DI
)
MOVOU
X5
,
112
(
DI
)
MOVOU
X7
,
128
(
DI
)
MOVOU
X9
,
144
(
DI
)
RET
vendor/golang.org/x/crypto/curve25519/curve25519.go
浏览文件 @
cf4faa49
...
...
@@ -8,6 +8,10 @@
package
curve25519
import
(
"encoding/binary"
)
// This code is a port of the public domain, "ref10" implementation of
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
...
...
@@ -50,17 +54,11 @@ func feCopy(dst, src *fieldElement) {
//
// Preconditions: b in {0,1}.
func
feCSwap
(
f
,
g
*
fieldElement
,
b
int32
)
{
var
x
fieldElement
b
=
-
b
for
i
:=
range
x
{
x
[
i
]
=
b
&
(
f
[
i
]
^
g
[
i
])
}
for
i
:=
range
f
{
f
[
i
]
^=
x
[
i
]
}
for
i
:=
range
g
{
g
[
i
]
^=
x
[
i
]
t
:=
b
&
(
f
[
i
]
^
g
[
i
])
f
[
i
]
^=
t
g
[
i
]
^=
t
}
}
...
...
@@ -75,12 +73,7 @@ func load3(in []byte) int64 {
// load4 reads a 32-bit, little-endian value from in.
func
load4
(
in
[]
byte
)
int64
{
var
r
int64
r
=
int64
(
in
[
0
])
r
|=
int64
(
in
[
1
])
<<
8
r
|=
int64
(
in
[
2
])
<<
16
r
|=
int64
(
in
[
3
])
<<
24
return
r
return
int64
(
binary
.
LittleEndian
.
Uint32
(
in
))
}
func
feFromBytes
(
dst
*
fieldElement
,
src
*
[
32
]
byte
)
{
...
...
vendor/golang.org/x/crypto/ssh/certs.go
浏览文件 @
cf4faa49
...
...
@@ -268,7 +268,7 @@ type CertChecker struct {
// HostKeyFallback is called when CertChecker.CheckHostKey encounters a
// public key that is not a certificate. It must implement host key
// validation or else, if nil, all such keys are rejected.
HostKeyFallback
func
(
addr
string
,
remote
net
.
Addr
,
key
PublicKey
)
error
HostKeyFallback
HostKeyCallback
// IsRevoked is called for each certificate so that revocation checking
// can be implemented. It should return true if the given certificate
...
...
vendor/golang.org/x/crypto/ssh/client.go
浏览文件 @
cf4faa49
...
...
@@ -5,6 +5,7 @@
package
ssh
import
(
"bytes"
"errors"
"fmt"
"net"
...
...
@@ -13,7 +14,7 @@ import (
)
// Client implements a traditional SSH client that supports shells,
// subprocesses,
port
forwarding and tunneled dialing.
// subprocesses,
TCP port/streamlocal
forwarding and tunneled dialing.
type
Client
struct
{
Conn
...
...
@@ -59,6 +60,7 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
conn
.
forwards
.
closeAll
()
}()
go
conn
.
forwards
.
handleChannels
(
conn
.
HandleChannelOpen
(
"forwarded-tcpip"
))
go
conn
.
forwards
.
handleChannels
(
conn
.
HandleChannelOpen
(
"forwarded-streamlocal@openssh.com"
))
return
conn
}
...
...
@@ -68,6 +70,11 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
func
NewClientConn
(
c
net
.
Conn
,
addr
string
,
config
*
ClientConfig
)
(
Conn
,
<-
chan
NewChannel
,
<-
chan
*
Request
,
error
)
{
fullConf
:=
*
config
fullConf
.
SetDefaults
()
if
fullConf
.
HostKeyCallback
==
nil
{
c
.
Close
()
return
nil
,
nil
,
nil
,
errors
.
New
(
"ssh: must specify HostKeyCallback"
)
}
conn
:=
&
connection
{
sshConn
:
sshConn
{
conn
:
c
},
}
...
...
@@ -173,6 +180,13 @@ func Dial(network, addr string, config *ClientConfig) (*Client, error) {
return
NewClient
(
c
,
chans
,
reqs
),
nil
}
// HostKeyCallback is the function type used for verifying server
// keys. A HostKeyCallback must return nil if the host key is OK, or
// an error to reject it. It receives the hostname as passed to Dial
// or NewClientConn. The remote address is the RemoteAddr of the
// net.Conn underlying the the SSH connection.
type
HostKeyCallback
func
(
hostname
string
,
remote
net
.
Addr
,
key
PublicKey
)
error
// A ClientConfig structure is used to configure a Client. It must not be
// modified after having been passed to an SSH function.
type
ClientConfig
struct
{
...
...
@@ -188,10 +202,12 @@ type ClientConfig struct {
// be used during authentication.
Auth
[]
AuthMethod
// HostKeyCallback, if not nil, is called during the cryptographic
// handshake to validate the server's host key. A nil HostKeyCallback
// implies that all host keys are accepted.
HostKeyCallback
func
(
hostname
string
,
remote
net
.
Addr
,
key
PublicKey
)
error
// HostKeyCallback is called during the cryptographic
// handshake to validate the server's host key. The client
// configuration must supply this callback for the connection
// to succeed. The functions InsecureIgnoreHostKey or
// FixedHostKey can be used for simplistic host key checks.
HostKeyCallback
HostKeyCallback
// ClientVersion contains the version identification string that will
// be used for the connection. If empty, a reasonable default is used.
...
...
@@ -209,3 +225,33 @@ type ClientConfig struct {
// A Timeout of zero means no timeout.
Timeout
time
.
Duration
}
// InsecureIgnoreHostKey returns a function that can be used for
// ClientConfig.HostKeyCallback to accept any host key. It should
// not be used for production code.
func
InsecureIgnoreHostKey
()
HostKeyCallback
{
return
func
(
hostname
string
,
remote
net
.
Addr
,
key
PublicKey
)
error
{
return
nil
}
}
type
fixedHostKey
struct
{
key
PublicKey
}
func
(
f
*
fixedHostKey
)
check
(
hostname
string
,
remote
net
.
Addr
,
key
PublicKey
)
error
{
if
f
.
key
==
nil
{
return
fmt
.
Errorf
(
"ssh: required host key was nil"
)
}
if
!
bytes
.
Equal
(
key
.
Marshal
(),
f
.
key
.
Marshal
())
{
return
fmt
.
Errorf
(
"ssh: host key mismatch"
)
}
return
nil
}
// FixedHostKey returns a function for use in
// ClientConfig.HostKeyCallback to accept only a specific host key.
func
FixedHostKey
(
key
PublicKey
)
HostKeyCallback
{
hk
:=
&
fixedHostKey
{
key
}
return
hk
.
check
}
vendor/golang.org/x/crypto/ssh/client_auth.go
浏览文件 @
cf4faa49
...
...
@@ -179,31 +179,26 @@ func (cb publicKeyCallback) method() string {
}
func
(
cb
publicKeyCallback
)
auth
(
session
[]
byte
,
user
string
,
c
packetConn
,
rand
io
.
Reader
)
(
bool
,
[]
string
,
error
)
{
// Authentication is performed
in two stages. The first stage sends an
//
enquiry to test if each key is acceptable to the remote. The second
//
stage attempts to authenticate with the valid keys obtained in the
//
first stage
.
// Authentication is performed
by sending an enquiry to test if a key is
//
acceptable to the remote. If the key is acceptable, the client will
//
attempt to authenticate with the valid key. If not the client will repeat
//
the process with the remaining keys
.
signers
,
err
:=
cb
()
if
err
!=
nil
{
return
false
,
nil
,
err
}
var
validKeys
[]
Signer
var
methods
[]
string
for
_
,
signer
:=
range
signers
{
if
ok
,
err
:=
validateKey
(
signer
.
PublicKey
(),
user
,
c
);
ok
{
validKeys
=
append
(
validKeys
,
signer
)
}
else
{
if
err
!=
nil
{
return
false
,
nil
,
err
}
ok
,
err
:=
validateKey
(
signer
.
PublicKey
(),
user
,
c
)
if
err
!=
nil
{
return
false
,
nil
,
err
}
if
!
ok
{
continue
}
}
// methods that may continue if this auth is not successful.
var
methods
[]
string
for
_
,
signer
:=
range
validKeys
{
pub
:=
signer
.
PublicKey
()
pubKey
:=
pub
.
Marshal
()
sign
,
err
:=
signer
.
Sign
(
rand
,
buildDataSignedForAuth
(
session
,
userAuthRequestMsg
{
User
:
user
,
...
...
@@ -236,13 +231,29 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
if
err
!=
nil
{
return
false
,
nil
,
err
}
if
success
{
// If authentication succeeds or the list of available methods does not
// contain the "publickey" method, do not attempt to authenticate with any
// other keys. According to RFC 4252 Section 7, the latter can occur when
// additional authentication methods are required.
if
success
||
!
containsMethod
(
methods
,
cb
.
method
())
{
return
success
,
methods
,
err
}
}
return
false
,
methods
,
nil
}
func
containsMethod
(
methods
[]
string
,
method
string
)
bool
{
for
_
,
m
:=
range
methods
{
if
m
==
method
{
return
true
}
}
return
false
}
// validateKey validates the key provided is acceptable to the server.
func
validateKey
(
key
PublicKey
,
user
string
,
c
packetConn
)
(
bool
,
error
)
{
pubKey
:=
key
.
Marshal
()
...
...
vendor/golang.org/x/crypto/ssh/common.go
浏览文件 @
cf4faa49
...
...
@@ -9,6 +9,7 @@ import (
"crypto/rand"
"fmt"
"io"
"math"
"sync"
_
"crypto/sha1"
...
...
@@ -40,7 +41,7 @@ var supportedKexAlgos = []string{
kexAlgoDH14SHA1
,
kexAlgoDH1SHA1
,
}
// supported
Kex
Algos specifies the supported host-key algorithms (i.e. methods
// supported
HostKey
Algos specifies the supported host-key algorithms (i.e. methods
// of authenticating servers) in preference order.
var
supportedHostKeyAlgos
=
[]
string
{
CertAlgoRSAv01
,
CertAlgoDSAv01
,
CertAlgoECDSA256v01
,
...
...
@@ -186,7 +187,7 @@ type Config struct {
// The maximum number of bytes sent or received after which a
// new key is negotiated. It must be at least 256. If
// unspecified,
1 gigabyte
is used.
// unspecified,
a size suitable for the chosen cipher
is used.
RekeyThreshold
uint64
// The allowed key exchanges algorithms. If unspecified then a
...
...
@@ -230,11 +231,12 @@ func (c *Config) SetDefaults() {
}
if
c
.
RekeyThreshold
==
0
{
// RFC 4253, section 9 suggests rekeying after 1G.
c
.
RekeyThreshold
=
1
<<
30
}
if
c
.
RekeyThreshold
<
minRekeyThreshold
{
// cipher specific default
}
else
if
c
.
RekeyThreshold
<
minRekeyThreshold
{
c
.
RekeyThreshold
=
minRekeyThreshold
}
else
if
c
.
RekeyThreshold
>=
math
.
MaxInt64
{
// Avoid weirdness if somebody uses -1 as a threshold.
c
.
RekeyThreshold
=
math
.
MaxInt64
}
}
...
...
vendor/golang.org/x/crypto/ssh/doc.go
浏览文件 @
cf4faa49
...
...
@@ -14,5 +14,8 @@ others.
References:
[PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
[SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1
This package does not fall under the stability promise of the Go language itself,
so its API may be changed when pressing needs arise.
*/
package
ssh
// import "golang.org/x/crypto/ssh"
vendor/golang.org/x/crypto/ssh/handshake.go
浏览文件 @
cf4faa49
...
...
@@ -74,7 +74,7 @@ type handshakeTransport struct {
startKex
chan
*
pendingKex
// data for host key checking
hostKeyCallback
func
(
hostname
string
,
remote
net
.
Addr
,
key
PublicKey
)
error
hostKeyCallback
HostKeyCallback
dialAddress
string
remoteAddr
net
.
Addr
...
...
@@ -107,6 +107,8 @@ func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion,
config
:
config
,
}
t
.
resetReadThresholds
()
t
.
resetWriteThresholds
()
// We always start with a mandatory key exchange.
t
.
requestKex
<-
struct
{}{}
...
...
@@ -237,6 +239,17 @@ func (t *handshakeTransport) requestKeyExchange() {
}
}
func
(
t
*
handshakeTransport
)
resetWriteThresholds
()
{
t
.
writePacketsLeft
=
packetRekeyThreshold
if
t
.
config
.
RekeyThreshold
>
0
{
t
.
writeBytesLeft
=
int64
(
t
.
config
.
RekeyThreshold
)
}
else
if
t
.
algorithms
!=
nil
{
t
.
writeBytesLeft
=
t
.
algorithms
.
w
.
rekeyBytes
()
}
else
{
t
.
writeBytesLeft
=
1
<<
30
}
}
func
(
t
*
handshakeTransport
)
kexLoop
()
{
write
:
...
...
@@ -285,12 +298,8 @@ write:
t
.
writeError
=
err
t
.
sentInitPacket
=
nil
t
.
sentInitMsg
=
nil
t
.
writePacketsLeft
=
packetRekeyThreshold
if
t
.
config
.
RekeyThreshold
>
0
{
t
.
writeBytesLeft
=
int64
(
t
.
config
.
RekeyThreshold
)
}
else
if
t
.
algorithms
!=
nil
{
t
.
writeBytesLeft
=
t
.
algorithms
.
w
.
rekeyBytes
()
}
t
.
resetWriteThresholds
()
// we have completed the key exchange. Since the
// reader is still blocked, it is safe to clear out
...
...
@@ -344,6 +353,17 @@ write:
// key exchange itself.
const
packetRekeyThreshold
=
(
1
<<
31
)
func
(
t
*
handshakeTransport
)
resetReadThresholds
()
{
t
.
readPacketsLeft
=
packetRekeyThreshold
if
t
.
config
.
RekeyThreshold
>
0
{
t
.
readBytesLeft
=
int64
(
t
.
config
.
RekeyThreshold
)
}
else
if
t
.
algorithms
!=
nil
{
t
.
readBytesLeft
=
t
.
algorithms
.
r
.
rekeyBytes
()
}
else
{
t
.
readBytesLeft
=
1
<<
30
}
}
func
(
t
*
handshakeTransport
)
readOnePacket
(
first
bool
)
([]
byte
,
error
)
{
p
,
err
:=
t
.
conn
.
readPacket
()
if
err
!=
nil
{
...
...
@@ -391,12 +411,7 @@ func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) {
return
nil
,
err
}
t
.
readPacketsLeft
=
packetRekeyThreshold
if
t
.
config
.
RekeyThreshold
>
0
{
t
.
readBytesLeft
=
int64
(
t
.
config
.
RekeyThreshold
)
}
else
{
t
.
readBytesLeft
=
t
.
algorithms
.
r
.
rekeyBytes
()
}
t
.
resetReadThresholds
()
// By default, a key exchange is hidden from higher layers by
// translating it into msgIgnore.
...
...
@@ -574,7 +589,9 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
}
result
.
SessionID
=
t
.
sessionID
t
.
conn
.
prepareKeyChange
(
t
.
algorithms
,
result
)
if
err
:=
t
.
conn
.
prepareKeyChange
(
t
.
algorithms
,
result
);
err
!=
nil
{
return
err
}
if
err
=
t
.
conn
.
writePacket
([]
byte
{
msgNewKeys
});
err
!=
nil
{
return
err
}
...
...
@@ -614,11 +631,9 @@ func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *
return
nil
,
err
}
if
t
.
hostKeyCallback
!=
nil
{
err
=
t
.
hostKeyCallback
(
t
.
dialAddress
,
t
.
remoteAddr
,
hostKey
)
if
err
!=
nil
{
return
nil
,
err
}
err
=
t
.
hostKeyCallback
(
t
.
dialAddress
,
t
.
remoteAddr
,
hostKey
)
if
err
!=
nil
{
return
nil
,
err
}
return
result
,
nil
...
...
vendor/golang.org/x/crypto/ssh/keys.go
浏览文件 @
cf4faa49
...
...
@@ -824,7 +824,7 @@ func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
// Implemented based on the documentation at
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
func
parseOpenSSHPrivateKey
(
key
[]
byte
)
(
*
ed25519
.
PrivateKey
,
error
)
{
func
parseOpenSSHPrivateKey
(
key
[]
byte
)
(
crypto
.
PrivateKey
,
error
)
{
magic
:=
append
([]
byte
(
"openssh-key-v1"
),
0
)
if
!
bytes
.
Equal
(
magic
,
key
[
0
:
len
(
magic
)])
{
return
nil
,
errors
.
New
(
"ssh: invalid openssh private key format"
)
...
...
@@ -844,14 +844,15 @@ func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
return
nil
,
err
}
if
w
.
KdfName
!=
"none"
||
w
.
CipherName
!=
"none"
{
return
nil
,
errors
.
New
(
"ssh: cannot decode encrypted private keys"
)
}
pk1
:=
struct
{
Check1
uint32
Check2
uint32
Keytype
string
Pub
[]
byte
Priv
[]
byte
Comment
string
Pad
[]
byte
`ssh:"rest"`
Rest
[]
byte
`ssh:"rest"`
}{}
if
err
:=
Unmarshal
(
w
.
PrivKeyBlock
,
&
pk1
);
err
!=
nil
{
...
...
@@ -862,24 +863,75 @@ func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
return
nil
,
errors
.
New
(
"ssh: checkint mismatch"
)
}
// we only handle ed25519 keys currently
if
pk1
.
Keytype
!=
KeyAlgoED25519
{
return
nil
,
errors
.
New
(
"ssh: unhandled key type"
)
}
// we only handle ed25519 and rsa keys currently
switch
pk1
.
Keytype
{
case
KeyAlgoRSA
:
// https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L2760-L2773
key
:=
struct
{
N
*
big
.
Int
E
*
big
.
Int
D
*
big
.
Int
Iqmp
*
big
.
Int
P
*
big
.
Int
Q
*
big
.
Int
Comment
string
Pad
[]
byte
`ssh:"rest"`
}{}
if
err
:=
Unmarshal
(
pk1
.
Rest
,
&
key
);
err
!=
nil
{
return
nil
,
err
}
for
i
,
b
:=
range
pk1
.
Pad
{
if
int
(
b
)
!=
i
+
1
{
return
nil
,
errors
.
New
(
"ssh: padding not as expected"
)
for
i
,
b
:=
range
key
.
Pad
{
if
int
(
b
)
!=
i
+
1
{
return
nil
,
errors
.
New
(
"ssh: padding not as expected"
)
}
}
}
if
len
(
pk1
.
Priv
)
!=
ed25519
.
PrivateKeySize
{
return
nil
,
errors
.
New
(
"ssh: private key unexpected length"
)
}
pk
:=
&
rsa
.
PrivateKey
{
PublicKey
:
rsa
.
PublicKey
{
N
:
key
.
N
,
E
:
int
(
key
.
E
.
Int64
()),
},
D
:
key
.
D
,
Primes
:
[]
*
big
.
Int
{
key
.
P
,
key
.
Q
},
}
pk
:=
ed25519
.
PrivateKey
(
make
([]
byte
,
ed25519
.
PrivateKeySize
))
copy
(
pk
,
pk1
.
Priv
)
return
&
pk
,
nil
if
err
:=
pk
.
Validate
();
err
!=
nil
{
return
nil
,
err
}
pk
.
Precompute
()
return
pk
,
nil
case
KeyAlgoED25519
:
key
:=
struct
{
Pub
[]
byte
Priv
[]
byte
Comment
string
Pad
[]
byte
`ssh:"rest"`
}{}
if
err
:=
Unmarshal
(
pk1
.
Rest
,
&
key
);
err
!=
nil
{
return
nil
,
err
}
if
len
(
key
.
Priv
)
!=
ed25519
.
PrivateKeySize
{
return
nil
,
errors
.
New
(
"ssh: private key unexpected length"
)
}
for
i
,
b
:=
range
key
.
Pad
{
if
int
(
b
)
!=
i
+
1
{
return
nil
,
errors
.
New
(
"ssh: padding not as expected"
)
}
}
pk
:=
ed25519
.
PrivateKey
(
make
([]
byte
,
ed25519
.
PrivateKeySize
))
copy
(
pk
,
key
.
Priv
)
return
&
pk
,
nil
default
:
return
nil
,
errors
.
New
(
"ssh: unhandled key type"
)
}
}
// FingerprintLegacyMD5 returns the user presentation of the key's
...
...
vendor/golang.org/x/crypto/ssh/server.go
浏览文件 @
cf4faa49
...
...
@@ -45,6 +45,12 @@ type ServerConfig struct {
// authenticating.
NoClientAuth
bool
// MaxAuthTries specifies the maximum number of authentication attempts
// permitted per connection. If set to a negative number, the number of
// attempts are unlimited. If set to zero, the number of attempts are limited
// to 6.
MaxAuthTries
int
// PasswordCallback, if non-nil, is called when a user
// attempts to authenticate using a password.
PasswordCallback
func
(
conn
ConnMetadata
,
password
[]
byte
)
(
*
Permissions
,
error
)
...
...
@@ -141,6 +147,10 @@ type ServerConn struct {
// Request and NewChannel channels must be serviced, or the connection
// will hang.
func
NewServerConn
(
c
net
.
Conn
,
config
*
ServerConfig
)
(
*
ServerConn
,
<-
chan
NewChannel
,
<-
chan
*
Request
,
error
)
{
if
config
.
MaxAuthTries
==
0
{
config
.
MaxAuthTries
=
6
}
fullConf
:=
*
config
fullConf
.
SetDefaults
()
s
:=
&
connection
{
...
...
@@ -267,8 +277,23 @@ func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, err
var
cache
pubKeyCache
var
perms
*
Permissions
authFailures
:=
0
userAuthLoop
:
for
{
if
authFailures
>=
config
.
MaxAuthTries
&&
config
.
MaxAuthTries
>
0
{
discMsg
:=
&
disconnectMsg
{
Reason
:
2
,
Message
:
"too many authentication failures"
,
}
if
err
:=
s
.
transport
.
writePacket
(
Marshal
(
discMsg
));
err
!=
nil
{
return
nil
,
err
}
return
nil
,
discMsg
}
var
userAuthReq
userAuthRequestMsg
if
packet
,
err
:=
s
.
transport
.
readPacket
();
err
!=
nil
{
return
nil
,
err
...
...
@@ -289,6 +314,11 @@ userAuthLoop:
if
config
.
NoClientAuth
{
authErr
=
nil
}
// allow initial attempt of 'none' without penalty
if
authFailures
==
0
{
authFailures
--
}
case
"password"
:
if
config
.
PasswordCallback
==
nil
{
authErr
=
errors
.
New
(
"ssh: password auth not configured"
)
...
...
@@ -360,6 +390,7 @@ userAuthLoop:
if
isQuery
{
// The client can query if the given public key
// would be okay.
if
len
(
payload
)
>
0
{
return
nil
,
parseError
(
msgUserAuthRequest
)
}
...
...
@@ -409,6 +440,8 @@ userAuthLoop:
break
userAuthLoop
}
authFailures
++
var
failureMsg
userAuthFailureMsg
if
config
.
PasswordCallback
!=
nil
{
failureMsg
.
Methods
=
append
(
failureMsg
.
Methods
,
"password"
)
...
...
vendor/golang.org/x/crypto/ssh/streamlocal.go
0 → 100644
浏览文件 @
cf4faa49
package
ssh
import
(
"errors"
"io"
"net"
)
// streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message
// with "direct-streamlocal@openssh.com" string.
//
// See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235
type
streamLocalChannelOpenDirectMsg
struct
{
socketPath
string
reserved0
string
reserved1
uint32
}
// forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message
// with "forwarded-streamlocal@openssh.com" string.
type
forwardedStreamLocalPayload
struct
{
SocketPath
string
Reserved0
string
}
// streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message
// with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string.
type
streamLocalChannelForwardMsg
struct
{
socketPath
string
}
// ListenUnix is similar to ListenTCP but uses a Unix domain socket.
func
(
c
*
Client
)
ListenUnix
(
socketPath
string
)
(
net
.
Listener
,
error
)
{
m
:=
streamLocalChannelForwardMsg
{
socketPath
,
}
// send message
ok
,
_
,
err
:=
c
.
SendRequest
(
"streamlocal-forward@openssh.com"
,
true
,
Marshal
(
&
m
))
if
err
!=
nil
{
return
nil
,
err
}
if
!
ok
{
return
nil
,
errors
.
New
(
"ssh: streamlocal-forward@openssh.com request denied by peer"
)
}
ch
:=
c
.
forwards
.
add
(
&
net
.
UnixAddr
{
Name
:
socketPath
,
Net
:
"unix"
})
return
&
unixListener
{
socketPath
,
c
,
ch
},
nil
}
func
(
c
*
Client
)
dialStreamLocal
(
socketPath
string
)
(
Channel
,
error
)
{
msg
:=
streamLocalChannelOpenDirectMsg
{
socketPath
:
socketPath
,
}
ch
,
in
,
err
:=
c
.
OpenChannel
(
"direct-streamlocal@openssh.com"
,
Marshal
(
&
msg
))
if
err
!=
nil
{
return
nil
,
err
}
go
DiscardRequests
(
in
)
return
ch
,
err
}
type
unixListener
struct
{
socketPath
string
conn
*
Client
in
<-
chan
forward
}
// Accept waits for and returns the next connection to the listener.
func
(
l
*
unixListener
)
Accept
()
(
net
.
Conn
,
error
)
{
s
,
ok
:=
<-
l
.
in
if
!
ok
{
return
nil
,
io
.
EOF
}
ch
,
incoming
,
err
:=
s
.
newCh
.
Accept
()
if
err
!=
nil
{
return
nil
,
err
}
go
DiscardRequests
(
incoming
)
return
&
chanConn
{
Channel
:
ch
,
laddr
:
&
net
.
UnixAddr
{
Name
:
l
.
socketPath
,
Net
:
"unix"
,
},
raddr
:
&
net
.
UnixAddr
{
Name
:
"@"
,
Net
:
"unix"
,
},
},
nil
}
// Close closes the listener.
func
(
l
*
unixListener
)
Close
()
error
{
// this also closes the listener.
l
.
conn
.
forwards
.
remove
(
&
net
.
UnixAddr
{
Name
:
l
.
socketPath
,
Net
:
"unix"
})
m
:=
streamLocalChannelForwardMsg
{
l
.
socketPath
,
}
ok
,
_
,
err
:=
l
.
conn
.
SendRequest
(
"cancel-streamlocal-forward@openssh.com"
,
true
,
Marshal
(
&
m
))
if
err
==
nil
&&
!
ok
{
err
=
errors
.
New
(
"ssh: cancel-streamlocal-forward@openssh.com failed"
)
}
return
err
}
// Addr returns the listener's network address.
func
(
l
*
unixListener
)
Addr
()
net
.
Addr
{
return
&
net
.
UnixAddr
{
Name
:
l
.
socketPath
,
Net
:
"unix"
,
}
}
vendor/golang.org/x/crypto/ssh/tcpip.go
浏览文件 @
cf4faa49
...
...
@@ -20,12 +20,20 @@ import (
// addr. Incoming connections will be available by calling Accept on
// the returned net.Listener. The listener must be serviced, or the
// SSH connection may hang.
// N must be "tcp", "tcp4", "tcp6", or "unix".
func
(
c
*
Client
)
Listen
(
n
,
addr
string
)
(
net
.
Listener
,
error
)
{
laddr
,
err
:=
net
.
ResolveTCPAddr
(
n
,
addr
)
if
err
!=
nil
{
return
nil
,
err
switch
n
{
case
"tcp"
,
"tcp4"
,
"tcp6"
:
laddr
,
err
:=
net
.
ResolveTCPAddr
(
n
,
addr
)
if
err
!=
nil
{
return
nil
,
err
}
return
c
.
ListenTCP
(
laddr
)
case
"unix"
:
return
c
.
ListenUnix
(
addr
)
default
:
return
nil
,
fmt
.
Errorf
(
"ssh: unsupported protocol: %s"
,
n
)
}
return
c
.
ListenTCP
(
laddr
)
}
// Automatic port allocation is broken with OpenSSH before 6.0. See
...
...
@@ -116,7 +124,7 @@ func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
}
// Register this forward, using the port number we obtained.
ch
:=
c
.
forwards
.
add
(
*
laddr
)
ch
:=
c
.
forwards
.
add
(
laddr
)
return
&
tcpListener
{
laddr
,
c
,
ch
},
nil
}
...
...
@@ -131,7 +139,7 @@ type forwardList struct {
// forwardEntry represents an established mapping of a laddr on a
// remote ssh server to a channel connected to a tcpListener.
type
forwardEntry
struct
{
laddr
net
.
TCP
Addr
laddr
net
.
Addr
c
chan
forward
}
...
...
@@ -139,16 +147,16 @@ type forwardEntry struct {
// arguments to add/remove/lookup should be address as specified in
// the original forward-request.
type
forward
struct
{
newCh
NewChannel
// the ssh client channel underlying this forward
raddr
*
net
.
TCPAddr
// the raddr of the incoming connection
newCh
NewChannel
// the ssh client channel underlying this forward
raddr
net
.
Addr
// the raddr of the incoming connection
}
func
(
l
*
forwardList
)
add
(
addr
net
.
TCP
Addr
)
chan
forward
{
func
(
l
*
forwardList
)
add
(
addr
net
.
Addr
)
chan
forward
{
l
.
Lock
()
defer
l
.
Unlock
()
f
:=
forwardEntry
{
addr
,
make
(
chan
forward
,
1
),
laddr
:
addr
,
c
:
make
(
chan
forward
,
1
),
}
l
.
entries
=
append
(
l
.
entries
,
f
)
return
f
.
c
...
...
@@ -176,44 +184,69 @@ func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) {
func
(
l
*
forwardList
)
handleChannels
(
in
<-
chan
NewChannel
)
{
for
ch
:=
range
in
{
var
payload
forwardedTCPPayload
if
err
:=
Unmarshal
(
ch
.
ExtraData
(),
&
payload
);
err
!=
nil
{
ch
.
Reject
(
ConnectionFailed
,
"could not parse forwarded-tcpip payload: "
+
err
.
Error
())
continue
var
(
laddr
net
.
Addr
raddr
net
.
Addr
err
error
)
switch
channelType
:=
ch
.
ChannelType
();
channelType
{
case
"forwarded-tcpip"
:
var
payload
forwardedTCPPayload
if
err
=
Unmarshal
(
ch
.
ExtraData
(),
&
payload
);
err
!=
nil
{
ch
.
Reject
(
ConnectionFailed
,
"could not parse forwarded-tcpip payload: "
+
err
.
Error
())
continue
}
// RFC 4254 section 7.2 specifies that incoming
// addresses should list the address, in string
// format. It is implied that this should be an IP
// address, as it would be impossible to connect to it
// otherwise.
laddr
,
err
=
parseTCPAddr
(
payload
.
Addr
,
payload
.
Port
)
if
err
!=
nil
{
ch
.
Reject
(
ConnectionFailed
,
err
.
Error
())
continue
}
raddr
,
err
=
parseTCPAddr
(
payload
.
OriginAddr
,
payload
.
OriginPort
)
if
err
!=
nil
{
ch
.
Reject
(
ConnectionFailed
,
err
.
Error
())
continue
}
case
"forwarded-streamlocal@openssh.com"
:
var
payload
forwardedStreamLocalPayload
if
err
=
Unmarshal
(
ch
.
ExtraData
(),
&
payload
);
err
!=
nil
{
ch
.
Reject
(
ConnectionFailed
,
"could not parse forwarded-streamlocal@openssh.com payload: "
+
err
.
Error
())
continue
}
laddr
=
&
net
.
UnixAddr
{
Name
:
payload
.
SocketPath
,
Net
:
"unix"
,
}
raddr
=
&
net
.
UnixAddr
{
Name
:
"@"
,
Net
:
"unix"
,
}
default
:
panic
(
fmt
.
Errorf
(
"ssh: unknown channel type %s"
,
channelType
))
}
// RFC 4254 section 7.2 specifies that incoming
// addresses should list the address, in string
// format. It is implied that this should be an IP
// address, as it would be impossible to connect to it
// otherwise.
laddr
,
err
:=
parseTCPAddr
(
payload
.
Addr
,
payload
.
Port
)
if
err
!=
nil
{
ch
.
Reject
(
ConnectionFailed
,
err
.
Error
())
continue
}
raddr
,
err
:=
parseTCPAddr
(
payload
.
OriginAddr
,
payload
.
OriginPort
)
if
err
!=
nil
{
ch
.
Reject
(
ConnectionFailed
,
err
.
Error
())
continue
}
if
ok
:=
l
.
forward
(
*
laddr
,
*
raddr
,
ch
);
!
ok
{
if
ok
:=
l
.
forward
(
laddr
,
raddr
,
ch
);
!
ok
{
// Section 7.2, implementations MUST reject spurious incoming
// connections.
ch
.
Reject
(
Prohibited
,
"no forward for address"
)
continue
}
}
}
// remove removes the forward entry, and the channel feeding its
// listener.
func
(
l
*
forwardList
)
remove
(
addr
net
.
TCP
Addr
)
{
func
(
l
*
forwardList
)
remove
(
addr
net
.
Addr
)
{
l
.
Lock
()
defer
l
.
Unlock
()
for
i
,
f
:=
range
l
.
entries
{
if
addr
.
IP
.
Equal
(
f
.
laddr
.
IP
)
&&
addr
.
Port
==
f
.
laddr
.
Port
{
if
addr
.
Network
()
==
f
.
laddr
.
Network
()
&&
addr
.
String
()
==
f
.
laddr
.
String
()
{
l
.
entries
=
append
(
l
.
entries
[
:
i
],
l
.
entries
[
i
+
1
:
]
...
)
close
(
f
.
c
)
return
...
...
@@ -231,12 +264,12 @@ func (l *forwardList) closeAll() {
l
.
entries
=
nil
}
func
(
l
*
forwardList
)
forward
(
laddr
,
raddr
net
.
TCP
Addr
,
ch
NewChannel
)
bool
{
func
(
l
*
forwardList
)
forward
(
laddr
,
raddr
net
.
Addr
,
ch
NewChannel
)
bool
{
l
.
Lock
()
defer
l
.
Unlock
()
for
_
,
f
:=
range
l
.
entries
{
if
laddr
.
IP
.
Equal
(
f
.
laddr
.
IP
)
&&
laddr
.
Port
==
f
.
laddr
.
Port
{
f
.
c
<-
forward
{
ch
,
&
raddr
}
if
laddr
.
Network
()
==
f
.
laddr
.
Network
()
&&
laddr
.
String
()
==
f
.
laddr
.
String
()
{
f
.
c
<-
forward
{
newCh
:
ch
,
raddr
:
raddr
}
return
true
}
}
...
...
@@ -262,7 +295,7 @@ func (l *tcpListener) Accept() (net.Conn, error) {
}
go
DiscardRequests
(
incoming
)
return
&
tcpC
hanConn
{
return
&
c
hanConn
{
Channel
:
ch
,
laddr
:
l
.
laddr
,
raddr
:
s
.
raddr
,
...
...
@@ -277,7 +310,7 @@ func (l *tcpListener) Close() error {
}
// this also closes the listener.
l
.
conn
.
forwards
.
remove
(
*
l
.
laddr
)
l
.
conn
.
forwards
.
remove
(
l
.
laddr
)
ok
,
_
,
err
:=
l
.
conn
.
SendRequest
(
"cancel-tcpip-forward"
,
true
,
Marshal
(
&
m
))
if
err
==
nil
&&
!
ok
{
err
=
errors
.
New
(
"ssh: cancel-tcpip-forward failed"
)
...
...
@@ -293,29 +326,52 @@ func (l *tcpListener) Addr() net.Addr {
// Dial initiates a connection to the addr from the remote host.
// The resulting connection has a zero LocalAddr() and RemoteAddr().
func
(
c
*
Client
)
Dial
(
n
,
addr
string
)
(
net
.
Conn
,
error
)
{
// Parse the address into host and numeric port.
host
,
portString
,
err
:=
net
.
SplitHostPort
(
addr
)
if
err
!=
nil
{
return
nil
,
err
}
port
,
err
:=
strconv
.
ParseUint
(
portString
,
10
,
16
)
if
err
!=
nil
{
return
nil
,
err
}
// Use a zero address for local and remote address.
zeroAddr
:=
&
net
.
TCPAddr
{
IP
:
net
.
IPv4zero
,
Port
:
0
,
}
ch
,
err
:=
c
.
dial
(
net
.
IPv4zero
.
String
(),
0
,
host
,
int
(
port
))
if
err
!=
nil
{
return
nil
,
err
var
ch
Channel
switch
n
{
case
"tcp"
,
"tcp4"
,
"tcp6"
:
// Parse the address into host and numeric port.
host
,
portString
,
err
:=
net
.
SplitHostPort
(
addr
)
if
err
!=
nil
{
return
nil
,
err
}
port
,
err
:=
strconv
.
ParseUint
(
portString
,
10
,
16
)
if
err
!=
nil
{
return
nil
,
err
}
ch
,
err
=
c
.
dial
(
net
.
IPv4zero
.
String
(),
0
,
host
,
int
(
port
))
if
err
!=
nil
{
return
nil
,
err
}
// Use a zero address for local and remote address.
zeroAddr
:=
&
net
.
TCPAddr
{
IP
:
net
.
IPv4zero
,
Port
:
0
,
}
return
&
chanConn
{
Channel
:
ch
,
laddr
:
zeroAddr
,
raddr
:
zeroAddr
,
},
nil
case
"unix"
:
var
err
error
ch
,
err
=
c
.
dialStreamLocal
(
addr
)
if
err
!=
nil
{
return
nil
,
err
}
return
&
chanConn
{
Channel
:
ch
,
laddr
:
&
net
.
UnixAddr
{
Name
:
"@"
,
Net
:
"unix"
,
},
raddr
:
&
net
.
UnixAddr
{
Name
:
addr
,
Net
:
"unix"
,
},
},
nil
default
:
return
nil
,
fmt
.
Errorf
(
"ssh: unsupported protocol: %s"
,
n
)
}
return
&
tcpChanConn
{
Channel
:
ch
,
laddr
:
zeroAddr
,
raddr
:
zeroAddr
,
},
nil
}
// DialTCP connects to the remote address raddr on the network net,
...
...
@@ -332,7 +388,7 @@ func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error)
if
err
!=
nil
{
return
nil
,
err
}
return
&
tcpC
hanConn
{
return
&
c
hanConn
{
Channel
:
ch
,
laddr
:
laddr
,
raddr
:
raddr
,
...
...
@@ -366,26 +422,26 @@ type tcpChan struct {
Channel
// the backing channel
}
//
tcpC
hanConn fulfills the net.Conn interface without
//
c
hanConn fulfills the net.Conn interface without
// the tcpChan having to hold laddr or raddr directly.
type
tcpC
hanConn
struct
{
type
c
hanConn
struct
{
Channel
laddr
,
raddr
net
.
Addr
}
// LocalAddr returns the local network address.
func
(
t
*
tcpC
hanConn
)
LocalAddr
()
net
.
Addr
{
func
(
t
*
c
hanConn
)
LocalAddr
()
net
.
Addr
{
return
t
.
laddr
}
// RemoteAddr returns the remote network address.
func
(
t
*
tcpC
hanConn
)
RemoteAddr
()
net
.
Addr
{
func
(
t
*
c
hanConn
)
RemoteAddr
()
net
.
Addr
{
return
t
.
raddr
}
// SetDeadline sets the read and write deadlines associated
// with the connection.
func
(
t
*
tcpC
hanConn
)
SetDeadline
(
deadline
time
.
Time
)
error
{
func
(
t
*
c
hanConn
)
SetDeadline
(
deadline
time
.
Time
)
error
{
if
err
:=
t
.
SetReadDeadline
(
deadline
);
err
!=
nil
{
return
err
}
...
...
@@ -396,12 +452,14 @@ func (t *tcpChanConn) SetDeadline(deadline time.Time) error {
// A zero value for t means Read will not time out.
// After the deadline, the error from Read will implement net.Error
// with Timeout() == true.
func
(
t
*
tcpChanConn
)
SetReadDeadline
(
deadline
time
.
Time
)
error
{
func
(
t
*
chanConn
)
SetReadDeadline
(
deadline
time
.
Time
)
error
{
// for compatibility with previous version,
// the error message contains "tcpChan"
return
errors
.
New
(
"ssh: tcpChan: deadline not supported"
)
}
// SetWriteDeadline exists to satisfy the net.Conn interface
// but is not implemented by this type. It always returns an error.
func
(
t
*
tcpC
hanConn
)
SetWriteDeadline
(
deadline
time
.
Time
)
error
{
func
(
t
*
c
hanConn
)
SetWriteDeadline
(
deadline
time
.
Time
)
error
{
return
errors
.
New
(
"ssh: tcpChan: deadline not supported"
)
}
vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
浏览文件 @
cf4faa49
...
...
@@ -14,14 +14,12 @@ import (
// State contains the state of a terminal.
type
State
struct
{
termios
syscall
.
Termios
state
*
unix
.
Termios
}
// IsTerminal returns true if the given file descriptor is a terminal.
func
IsTerminal
(
fd
int
)
bool
{
// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
var
termio
unix
.
Termio
err
:=
unix
.
IoctlSetTermio
(
fd
,
unix
.
TCGETA
,
&
termio
)
_
,
err
:=
unix
.
IoctlGetTermio
(
fd
,
unix
.
TCGETA
)
return
err
==
nil
}
...
...
@@ -71,3 +69,60 @@ func ReadPassword(fd int) ([]byte, error) {
return
ret
,
nil
}
// MakeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
// see http://cr.illumos.org/~webrev/andy_js/1060/
func
MakeRaw
(
fd
int
)
(
*
State
,
error
)
{
oldTermiosPtr
,
err
:=
unix
.
IoctlGetTermios
(
fd
,
unix
.
TCGETS
)
if
err
!=
nil
{
return
nil
,
err
}
oldTermios
:=
*
oldTermiosPtr
newTermios
:=
oldTermios
newTermios
.
Iflag
&^=
syscall
.
IGNBRK
|
syscall
.
BRKINT
|
syscall
.
PARMRK
|
syscall
.
ISTRIP
|
syscall
.
INLCR
|
syscall
.
IGNCR
|
syscall
.
ICRNL
|
syscall
.
IXON
newTermios
.
Oflag
&^=
syscall
.
OPOST
newTermios
.
Lflag
&^=
syscall
.
ECHO
|
syscall
.
ECHONL
|
syscall
.
ICANON
|
syscall
.
ISIG
|
syscall
.
IEXTEN
newTermios
.
Cflag
&^=
syscall
.
CSIZE
|
syscall
.
PARENB
newTermios
.
Cflag
|=
syscall
.
CS8
newTermios
.
Cc
[
unix
.
VMIN
]
=
1
newTermios
.
Cc
[
unix
.
VTIME
]
=
0
if
err
:=
unix
.
IoctlSetTermios
(
fd
,
unix
.
TCSETS
,
&
newTermios
);
err
!=
nil
{
return
nil
,
err
}
return
&
State
{
state
:
oldTermiosPtr
,
},
nil
}
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func
Restore
(
fd
int
,
oldState
*
State
)
error
{
return
unix
.
IoctlSetTermios
(
fd
,
unix
.
TCSETS
,
oldState
.
state
)
}
// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func
GetState
(
fd
int
)
(
*
State
,
error
)
{
oldTermiosPtr
,
err
:=
unix
.
IoctlGetTermios
(
fd
,
unix
.
TCGETS
)
if
err
!=
nil
{
return
nil
,
err
}
return
&
State
{
state
:
oldTermiosPtr
,
},
nil
}
// GetSize returns the dimensions of the given terminal.
func
GetSize
(
fd
int
)
(
width
,
height
int
,
err
error
)
{
ws
,
err
:=
unix
.
IoctlGetWinsize
(
fd
,
unix
.
TIOCGWINSZ
)
if
err
!=
nil
{
return
0
,
0
,
err
}
return
int
(
ws
.
Col
),
int
(
ws
.
Row
),
nil
}
vendor/vendor.json
浏览文件 @
cf4faa49
...
...
@@ -384,92 +384,92 @@
{
"checksumSHA1"
:
"TT1rac6kpQp2vz24m5yDGUNQ/QQ="
,
"path"
:
"golang.org/x/crypto/cast5"
,
"revision"
:
"
453249f01cfeb54c3d549ddb75ff152ca243f9d8
"
,
"revisionTime"
:
"2017-0
2-08T20:51:15
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"
C1KKOxFoW7/W/NFNpiXK+boguNo
="
,
"checksumSHA1"
:
"
nAu0XmCeC6WnUySyI8R7w4cxAqU
="
,
"path"
:
"golang.org/x/crypto/curve25519"
,
"revision"
:
"
459e26527287adbc2adcc5d0d49abff9a5f315a7
"
,
"revisionTime"
:
"2017-0
3-17T13:29:17
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"wGb//LjBPNxYHqk+dcLo7BjPXK8="
,
"path"
:
"golang.org/x/crypto/ed25519"
,
"revision"
:
"
459e26527287adbc2adcc5d0d49abff9a5f315a7
"
,
"revisionTime"
:
"2017-0
3-17T13:29:17
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"LXFcVx8I587SnWmKycSDEq9yvK8="
,
"path"
:
"golang.org/x/crypto/ed25519/internal/edwards25519"
,
"revision"
:
"
459e26527287adbc2adcc5d0d49abff9a5f315a7
"
,
"revisionTime"
:
"2017-0
3-17T13:29:17
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"IIhFTrLlmlc6lEFSitqi4aw2lw0="
,
"path"
:
"golang.org/x/crypto/openpgp"
,
"revision"
:
"
453249f01cfeb54c3d549ddb75ff152ca243f9d8
"
,
"revisionTime"
:
"2017-0
2-08T20:51:15
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"olOKkhrdkYQHZ0lf1orrFQPQrv4="
,
"path"
:
"golang.org/x/crypto/openpgp/armor"
,
"revision"
:
"
453249f01cfeb54c3d549ddb75ff152ca243f9d8
"
,
"revisionTime"
:
"2017-0
2-08T20:51:15
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"eo/KtdjieJQXH7Qy+faXFcF70ME="
,
"path"
:
"golang.org/x/crypto/openpgp/elgamal"
,
"revision"
:
"
453249f01cfeb54c3d549ddb75ff152ca243f9d8
"
,
"revisionTime"
:
"2017-0
2-08T20:51:15
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"rlxVSaGgqdAgwblsErxTxIfuGfg="
,
"path"
:
"golang.org/x/crypto/openpgp/errors"
,
"revision"
:
"
453249f01cfeb54c3d549ddb75ff152ca243f9d8
"
,
"revisionTime"
:
"2017-0
2-08T20:51:15
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"LWdaR8Q9yn6eBCcnGl0HvJRDUBE="
,
"path"
:
"golang.org/x/crypto/openpgp/packet"
,
"revision"
:
"
453249f01cfeb54c3d549ddb75ff152ca243f9d8
"
,
"revisionTime"
:
"2017-0
2-08T20:51:15
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"s2qT4UwvzBSkzXuiuMkowif1Olw="
,
"path"
:
"golang.org/x/crypto/openpgp/s2k"
,
"revision"
:
"
453249f01cfeb54c3d549ddb75ff152ca243f9d8
"
,
"revisionTime"
:
"2017-0
2-08T20:51:15
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"1MGpGDQqnUoRpv7VEcQrXOBydXE="
,
"path"
:
"golang.org/x/crypto/pbkdf2"
,
"revision"
:
"
453249f01cfeb54c3d549ddb75ff152ca243f9d8
"
,
"revisionTime"
:
"2017-0
2-08T20:51:15
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"y/oIaxq2d3WPizRZfVjo8RCRYTU="
,
"path"
:
"golang.org/x/crypto/ripemd160"
,
"revision"
:
"
453249f01cfeb54c3d549ddb75ff152ca243f9d8
"
,
"revisionTime"
:
"2017-0
2-08T20:51:15
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"E8pDMGySfy5Mw+jzXOkOxo35bww="
,
"path"
:
"golang.org/x/crypto/scrypt"
,
"revision"
:
"
453249f01cfeb54c3d549ddb75ff152ca243f9d8
"
,
"revisionTime"
:
"2017-0
2-08T20:51:15
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"
fsrFs762jlaILyqqQImS1GfvIvw
="
,
"checksumSHA1"
:
"
8sVsMTphul+B0sI0qAv4TE1ZxUk
="
,
"path"
:
"golang.org/x/crypto/ssh"
,
"revision"
:
"
459e26527287adbc2adcc5d0d49abff9a5f315a7
"
,
"revisionTime"
:
"2017-0
3-17T13:29:17
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"
xiderUuvye8Kpn7yX3niiJg32bE
="
,
"checksumSHA1"
:
"
ZaU56svwLgiJD0y8JOB3+/mpYBA
="
,
"path"
:
"golang.org/x/crypto/ssh/terminal"
,
"revision"
:
"
459e26527287adbc2adcc5d0d49abff9a5f315a7
"
,
"revisionTime"
:
"2017-0
3-17T13:29:17
Z"
"revision"
:
"
c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
"
,
"revisionTime"
:
"2017-0
4-25T18:31:00
Z"
},
{
"checksumSHA1"
:
"Y+HGqEkYM15ir+J93MEaHdyFy0c="
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录