@ -0,0 +1,6 @@ | |||
module github.com/xanzy/ssh-agent | |||
require ( | |||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2 | |||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0 // indirect | |||
) |
@ -0,0 +1,4 @@ | |||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2 h1:NwxKRvbkH5MsNkvOtPZi3/3kmI8CAzs3mtv+GLQMkNo= | |||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | |||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0 h1:bzeyCHgoAyjZjAhvTpks+qM7sdlh4cCSitmXeCEO3B4= | |||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
@ -0,0 +1,73 @@ | |||
// Copyright 2019 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. | |||
// +build go1.13 | |||
// Package ed25519 implements the Ed25519 signature algorithm. See | |||
// https://ed25519.cr.yp.to/. | |||
// | |||
// These functions are also compatible with the “Ed25519” function defined in | |||
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key | |||
// representation includes a public key suffix to make multiple signing | |||
// operations with the same key more efficient. This package refers to the RFC | |||
// 8032 private key as the “seed”. | |||
// | |||
// Beginning with Go 1.13, the functionality of this package was moved to the | |||
// standard library as crypto/ed25519. This package only acts as a compatibility | |||
// wrapper. | |||
package ed25519 | |||
import ( | |||
"crypto/ed25519" | |||
"io" | |||
) | |||
const ( | |||
// PublicKeySize is the size, in bytes, of public keys as used in this package. | |||
PublicKeySize = 32 | |||
// PrivateKeySize is the size, in bytes, of private keys as used in this package. | |||
PrivateKeySize = 64 | |||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package. | |||
SignatureSize = 64 | |||
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032. | |||
SeedSize = 32 | |||
) | |||
// PublicKey is the type of Ed25519 public keys. | |||
// | |||
// This type is an alias for crypto/ed25519's PublicKey type. | |||
// See the crypto/ed25519 package for the methods on this type. | |||
type PublicKey = ed25519.PublicKey | |||
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. | |||
// | |||
// This type is an alias for crypto/ed25519's PrivateKey type. | |||
// See the crypto/ed25519 package for the methods on this type. | |||
type PrivateKey = ed25519.PrivateKey | |||
// GenerateKey generates a public/private key pair using entropy from rand. | |||
// If rand is nil, crypto/rand.Reader will be used. | |||
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { | |||
return ed25519.GenerateKey(rand) | |||
} | |||
// NewKeyFromSeed calculates a private key from a seed. It will panic if | |||
// len(seed) is not SeedSize. This function is provided for interoperability | |||
// with RFC 8032. RFC 8032's private keys correspond to seeds in this | |||
// package. | |||
func NewKeyFromSeed(seed []byte) PrivateKey { | |||
return ed25519.NewKeyFromSeed(seed) | |||
} | |||
// Sign signs the message with privateKey and returns a signature. It will | |||
// panic if len(privateKey) is not PrivateKeySize. | |||
func Sign(privateKey PrivateKey, message []byte) []byte { | |||
return ed25519.Sign(privateKey, message) | |||
} | |||
// Verify reports whether sig is a valid signature of message by publicKey. It | |||
// will panic if len(publicKey) is not PublicKeySize. | |||
func Verify(publicKey PublicKey, message, sig []byte) bool { | |||
return ed25519.Verify(publicKey, message, sig) | |||
} |
@ -0,0 +1,668 @@ | |||
// Copyright 2019 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. | |||
// Based on CRYPTOGAMS code with the following comment: | |||
// # ==================================================================== | |||
// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL | |||
// # project. The module is, however, dual licensed under OpenSSL and | |||
// # CRYPTOGAMS licenses depending on where you obtain it. For further | |||
// # details see http://www.openssl.org/~appro/cryptogams/. | |||
// # ==================================================================== | |||
// Original code can be found at the link below: | |||
// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91e5c39ca79126a4a876d5d8ff | |||
// There are some differences between CRYPTOGAMS code and this one. The round | |||
// loop for "_int" isn't the same as the original. Some adjustments were | |||
// necessary because there are less vector registers available. For example, some | |||
// X variables (r12, r13, r14, and r15) share the same register used by the | |||
// counter. The original code uses ctr to name the counter. Here we use CNT | |||
// because golang uses CTR as the counter register name. | |||
// +build ppc64le,!gccgo,!appengine | |||
#include "textflag.h" | |||
#define OUT R3 | |||
#define INP R4 | |||
#define LEN R5 | |||
#define KEY R6 | |||
#define CNT R7 | |||
#define TEMP R8 | |||
#define X0 R11 | |||
#define X1 R12 | |||
#define X2 R14 | |||
#define X3 R15 | |||
#define X4 R16 | |||
#define X5 R17 | |||
#define X6 R18 | |||
#define X7 R19 | |||
#define X8 R20 | |||
#define X9 R21 | |||
#define X10 R22 | |||
#define X11 R23 | |||
#define X12 R24 | |||
#define X13 R25 | |||
#define X14 R26 | |||
#define X15 R27 | |||
#define CON0 X0 | |||
#define CON1 X1 | |||
#define CON2 X2 | |||
#define CON3 X3 | |||
#define KEY0 X4 | |||
#define KEY1 X5 | |||
#define KEY2 X6 | |||
#define KEY3 X7 | |||
#define KEY4 X8 | |||
#define KEY5 X9 | |||
#define KEY6 X10 | |||
#define KEY7 X11 | |||
#define CNT0 X12 | |||
#define CNT1 X13 | |||
#define CNT2 X14 | |||
#define CNT3 X15 | |||
#define TMP0 R9 | |||
#define TMP1 R10 | |||
#define TMP2 R28 | |||
#define TMP3 R29 | |||
#define CONSTS R8 | |||
#define A0 V0 | |||
#define B0 V1 | |||
#define C0 V2 | |||
#define D0 V3 | |||
#define A1 V4 | |||
#define B1 V5 | |||
#define C1 V6 | |||
#define D1 V7 | |||
#define A2 V8 | |||
#define B2 V9 | |||
#define C2 V10 | |||
#define D2 V11 | |||
#define T0 V12 | |||
#define T1 V13 | |||
#define T2 V14 | |||
#define K0 V15 | |||
#define K1 V16 | |||
#define K2 V17 | |||
#define K3 V18 | |||
#define K4 V19 | |||
#define K5 V20 | |||
#define FOUR V21 | |||
#define SIXTEEN V22 | |||
#define TWENTY4 V23 | |||
#define TWENTY V24 | |||
#define TWELVE V25 | |||
#define TWENTY5 V26 | |||
#define SEVEN V27 | |||
#define INPPERM V28 | |||
#define OUTPERM V29 | |||
#define OUTMASK V30 | |||
#define DD0 V31 | |||
#define DD1 SEVEN | |||
#define DD2 T0 | |||
#define DD3 T1 | |||
#define DD4 T2 | |||
DATA ·consts+0x00(SB)/8, $0x3320646e61707865 | |||
DATA ·consts+0x08(SB)/8, $0x6b20657479622d32 | |||
DATA ·consts+0x10(SB)/8, $0x0000000000000001 | |||
DATA ·consts+0x18(SB)/8, $0x0000000000000000 | |||
DATA ·consts+0x20(SB)/8, $0x0000000000000004 | |||
DATA ·consts+0x28(SB)/8, $0x0000000000000000 | |||
DATA ·consts+0x30(SB)/8, $0x0a0b08090e0f0c0d | |||
DATA ·consts+0x38(SB)/8, $0x0203000106070405 | |||
DATA ·consts+0x40(SB)/8, $0x090a0b080d0e0f0c | |||
DATA ·consts+0x48(SB)/8, $0x0102030005060704 | |||
GLOBL ·consts(SB), RODATA, $80 | |||
//func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[32]byte, counter *[16]byte) | |||
TEXT ·chaCha20_ctr32_vmx(SB),NOSPLIT|NOFRAME,$0 | |||
// Load the arguments inside the registers | |||
MOVD out+0(FP), OUT | |||
MOVD inp+8(FP), INP | |||
MOVD len+16(FP), LEN | |||
MOVD key+24(FP), KEY | |||
MOVD counter+32(FP), CNT | |||
MOVD $·consts(SB), CONSTS // point to consts addr | |||
MOVD $16, X0 | |||
MOVD $32, X1 | |||
MOVD $48, X2 | |||
MOVD $64, X3 | |||
MOVD $31, X4 | |||
MOVD $15, X5 | |||
// Load key | |||
LVX (KEY)(R0), K1 | |||
LVSR (KEY)(R0), T0 | |||
LVX (KEY)(X0), K2 | |||
LVX (KEY)(X4), DD0 | |||
// Load counter | |||
LVX (CNT)(R0), K3 | |||
LVSR (CNT)(R0), T1 | |||
LVX (CNT)(X5), DD1 | |||
// Load constants | |||
LVX (CONSTS)(R0), K0 | |||
LVX (CONSTS)(X0), K5 | |||
LVX (CONSTS)(X1), FOUR | |||
LVX (CONSTS)(X2), SIXTEEN | |||
LVX (CONSTS)(X3), TWENTY4 | |||
// Align key and counter | |||
VPERM K2, K1, T0, K1 | |||
VPERM DD0, K2, T0, K2 | |||
VPERM DD1, K3, T1, K3 | |||
// Load counter to GPR | |||
MOVWZ 0(CNT), CNT0 | |||
MOVWZ 4(CNT), CNT1 | |||
MOVWZ 8(CNT), CNT2 | |||
MOVWZ 12(CNT), CNT3 | |||
// Adjust vectors for the initial state | |||
VADDUWM K3, K5, K3 | |||
VADDUWM K3, K5, K4 | |||
VADDUWM K4, K5, K5 | |||
// Synthesized constants | |||
VSPLTISW $-12, TWENTY | |||
VSPLTISW $12, TWELVE | |||
VSPLTISW $-7, TWENTY5 | |||
VXOR T0, T0, T0 | |||
VSPLTISW $-1, OUTMASK | |||
LVSR (INP)(R0), INPPERM | |||
LVSL (OUT)(R0), OUTPERM | |||
VPERM OUTMASK, T0, OUTPERM, OUTMASK | |||
loop_outer_vmx: | |||
// Load constant | |||
MOVD $0x61707865, CON0 | |||
MOVD $0x3320646e, CON1 | |||
MOVD $0x79622d32, CON2 | |||
MOVD $0x6b206574, CON3 | |||
VOR K0, K0, A0 | |||
VOR K0, K0, A1 | |||
VOR K0, K0, A2 | |||
VOR K1, K1, B0 | |||
MOVD $10, TEMP | |||
// Load key to GPR | |||
MOVWZ 0(KEY), X4 | |||
MOVWZ 4(KEY), X5 | |||
MOVWZ 8(KEY), X6 | |||
MOVWZ 12(KEY), X7 | |||
VOR K1, K1, B1 | |||
VOR K1, K1, B2 | |||
MOVWZ 16(KEY), X8 | |||
MOVWZ 0(CNT), X12 | |||
MOVWZ 20(KEY), X9 | |||
MOVWZ 4(CNT), X13 | |||
VOR K2, K2, C0 | |||
VOR K2, K2, C1 | |||
MOVWZ 24(KEY), X10 | |||
MOVWZ 8(CNT), X14 | |||
VOR K2, K2, C2 | |||
VOR K3, K3, D0 | |||
MOVWZ 28(KEY), X11 | |||
MOVWZ 12(CNT), X15 | |||
VOR K4, K4, D1 | |||
VOR K5, K5, D2 | |||
MOVD X4, TMP0 | |||
MOVD X5, TMP1 | |||
MOVD X6, TMP2 | |||
MOVD X7, TMP3 | |||
VSPLTISW $7, SEVEN | |||
MOVD TEMP, CTR | |||
loop_vmx: | |||
// CRYPTOGAMS uses a macro to create a loop using perl. This isn't possible | |||
// using assembly macros. Therefore, the macro expansion result was used | |||
// in order to maintain the algorithm efficiency. | |||
// This loop generates three keystream blocks using VMX instructions and, | |||
// in parallel, one keystream block using scalar instructions. | |||
ADD X4, X0, X0 | |||
ADD X5, X1, X1 | |||
VADDUWM A0, B0, A0 | |||
VADDUWM A1, B1, A1 | |||
ADD X6, X2, X2 | |||
ADD X7, X3, X3 | |||
VADDUWM A2, B2, A2 | |||
VXOR D0, A0, D0 | |||
XOR X0, X12, X12 | |||
XOR X1, X13, X13 | |||
VXOR D1, A1, D1 | |||
VXOR D2, A2, D2 | |||
XOR X2, X14, X14 | |||
XOR X3, X15, X15 | |||
VPERM D0, D0, SIXTEEN, D0 | |||
VPERM D1, D1, SIXTEEN, D1 | |||
ROTLW $16, X12, X12 | |||
ROTLW $16, X13, X13 | |||
VPERM D2, D2, SIXTEEN, D2 | |||
VADDUWM C0, D0, C0 | |||
ROTLW $16, X14, X14 | |||
ROTLW $16, X15, X15 | |||
VADDUWM C1, D1, C1 | |||
VADDUWM C2, D2, C2 | |||
ADD X12, X8, X8 | |||
ADD X13, X9, X9 | |||
VXOR B0, C0, T0 | |||
VXOR B1, C1, T1 | |||
ADD X14, X10, X10 | |||
ADD X15, X11, X11 | |||
VXOR B2, C2, T2 | |||
VRLW T0, TWELVE, B0 | |||
XOR X8, X4, X4 | |||
XOR X9, X5, X5 | |||
VRLW T1, TWELVE, B1 | |||
VRLW T2, TWELVE, B2 | |||
XOR X10, X6, X6 | |||
XOR X11, X7, X7 | |||
VADDUWM A0, B0, A0 | |||
VADDUWM A1, B1, A1 | |||
ROTLW $12, X4, X4 | |||
ROTLW $12, X5, X5 | |||
VADDUWM A2, B2, A2 | |||
VXOR D0, A0, D0 | |||
ROTLW $12, X6, X6 | |||
ROTLW $12, X7, X7 | |||
VXOR D1, A1, D1 | |||
VXOR D2, A2, D2 | |||
ADD X4, X0, X0 | |||
ADD X5, X1, X1 | |||
VPERM D0, D0, TWENTY4, D0 | |||
VPERM D1, D1, TWENTY4, D1 | |||
ADD X6, X2, X2 | |||
ADD X7, X3, X3 | |||
VPERM D2, D2, TWENTY4, D2 | |||
VADDUWM C0, D0, C0 | |||
XOR X0, X12, X12 | |||
XOR X1, X13, X13 | |||
VADDUWM C1, D1, C1 | |||
VADDUWM C2, D2, C2 | |||
XOR X2, X14, X14 | |||
XOR X3, X15, X15 | |||
VXOR B0, C0, T0 | |||
VXOR B1, C1, T1 | |||
ROTLW $8, X12, X12 | |||
ROTLW $8, X13, X13 | |||
VXOR B2, C2, T2 | |||
VRLW T0, SEVEN, B0 | |||
ROTLW $8, X14, X14 | |||
ROTLW $8, X15, X15 | |||
VRLW T1, SEVEN, B1 | |||
VRLW T2, SEVEN, B2 | |||
ADD X12, X8, X8 | |||
ADD X13, X9, X9 | |||
VSLDOI $8, C0, C0, C0 | |||
VSLDOI $8, C1, C1, C1 | |||
ADD X14, X10, X10 | |||
ADD X15, X11, X11 | |||
VSLDOI $8, C2, C2, C2 | |||
VSLDOI $12, B0, B0, B0 | |||
XOR X8, X4, X4 | |||
XOR X9, X5, X5 | |||
VSLDOI $12, B1, B1, B1 | |||
VSLDOI $12, B2, B2, B2 | |||
XOR X10, X6, X6 | |||
XOR X11, X7, X7 | |||
VSLDOI $4, D0, D0, D0 | |||
VSLDOI $4, D1, D1, D1 | |||
ROTLW $7, X4, X4 | |||
ROTLW $7, X5, X5 | |||
VSLDOI $4, D2, D2, D2 | |||
VADDUWM A0, B0, A0 | |||
ROTLW $7, X6, X6 | |||
ROTLW $7, X7, X7 | |||
VADDUWM A1, B1, A1 | |||
VADDUWM A2, B2, A2 | |||
ADD X5, X0, X0 | |||
ADD X6, X1, X1 | |||
VXOR D0, A0, D0 | |||
VXOR D1, A1, D1 | |||
ADD X7, X2, X2 | |||
ADD X4, X3, X3 | |||
VXOR D2, A2, D2 | |||
VPERM D0, D0, SIXTEEN, D0 | |||
XOR X0, X15, X15 | |||
XOR X1, X12, X12 | |||
VPERM D1, D1, SIXTEEN, D1 | |||
VPERM D2, D2, SIXTEEN, D2 | |||
XOR X2, X13, X13 | |||
XOR X3, X14, X14 | |||
VADDUWM C0, D0, C0 | |||
VADDUWM C1, D1, C1 | |||
ROTLW $16, X15, X15 | |||
ROTLW $16, X12, X12 | |||
VADDUWM C2, D2, C2 | |||
VXOR B0, C0, T0 | |||
ROTLW $16, X13, X13 | |||
ROTLW $16, X14, X14 | |||
VXOR B1, C1, T1 | |||
VXOR B2, C2, T2 | |||
ADD X15, X10, X10 | |||
ADD X12, X11, X11 | |||
VRLW T0, TWELVE, B0 | |||
VRLW T1, TWELVE, B1 | |||
ADD X13, X8, X8 | |||
ADD X14, X9, X9 | |||
VRLW T2, TWELVE, B2 | |||
VADDUWM A0, B0, A0 | |||
XOR X10, X5, X5 | |||
XOR X11, X6, X6 | |||
VADDUWM A1, B1, A1 | |||
VADDUWM A2, B2, A2 | |||
XOR X8, X7, X7 | |||
XOR X9, X4, X4 | |||
VXOR D0, A0, D0 | |||
VXOR D1, A1, D1 | |||
ROTLW $12, X5, X5 | |||
ROTLW $12, X6, X6 | |||
VXOR D2, A2, D2 | |||
VPERM D0, D0, TWENTY4, D0 | |||
ROTLW $12, X7, X7 | |||
ROTLW $12, X4, X4 | |||
VPERM D1, D1, TWENTY4, D1 | |||
VPERM D2, D2, TWENTY4, D2 | |||
ADD X5, X0, X0 | |||
ADD X6, X1, X1 | |||
VADDUWM C0, D0, C0 | |||
VADDUWM C1, D1, C1 | |||
ADD X7, X2, X2 | |||
ADD X4, X3, X3 | |||
VADDUWM C2, D2, C2 | |||
VXOR B0, C0, T0 | |||
XOR X0, X15, X15 | |||
XOR X1, X12, X12 | |||
VXOR B1, C1, T1 | |||
VXOR B2, C2, T2 | |||
XOR X2, X13, X13 | |||
XOR X3, X14, X14 | |||
VRLW T0, SEVEN, B0 | |||
VRLW T1, SEVEN, B1 | |||
ROTLW $8, X15, X15 | |||
ROTLW $8, X12, X12 | |||
VRLW T2, SEVEN, B2 | |||
VSLDOI $8, C0, C0, C0 | |||
ROTLW $8, X13, X13 | |||
ROTLW $8, X14, X14 | |||
VSLDOI $8, C1, C1, C1 | |||
VSLDOI $8, C2, C2, C2 | |||
ADD X15, X10, X10 | |||
ADD X12, X11, X11 | |||
VSLDOI $4, B0, B0, B0 | |||
VSLDOI $4, B1, B1, B1 | |||
ADD X13, X8, X8 | |||
ADD X14, X9, X9 | |||
VSLDOI $4, B2, B2, B2 | |||
VSLDOI $12, D0, D0, D0 | |||
XOR X10, X5, X5 | |||
XOR X11, X6, X6 | |||
VSLDOI $12, D1, D1, D1 | |||
VSLDOI $12, D2, D2, D2 | |||
XOR X8, X7, X7 | |||
XOR X9, X4, X4 | |||
ROTLW $7, X5, X5 | |||
ROTLW $7, X6, X6 | |||
ROTLW $7, X7, X7 | |||
ROTLW $7, X4, X4 | |||
BC 0x10, 0, loop_vmx | |||
SUB $256, LEN, LEN | |||
// Accumulate key block | |||
ADD $0x61707865, X0, X0 | |||
ADD $0x3320646e, X1, X1 | |||
ADD $0x79622d32, X2, X2 | |||
ADD $0x6b206574, X3, X3 | |||
ADD TMP0, X4, X4 | |||
ADD TMP1, X5, X5 | |||
ADD TMP2, X6, X6 | |||
ADD TMP3, X7, X7 | |||
MOVWZ 16(KEY), TMP0 | |||
MOVWZ 20(KEY), TMP1 | |||
MOVWZ 24(KEY), TMP2 | |||
MOVWZ 28(KEY), TMP3 | |||
ADD TMP0, X8, X8 | |||
ADD TMP1, X9, X9 | |||
ADD TMP2, X10, X10 | |||
ADD TMP3, X11, X11 | |||
MOVWZ 12(CNT), TMP0 | |||
MOVWZ 8(CNT), TMP1 | |||
MOVWZ 4(CNT), TMP2 | |||
MOVWZ 0(CNT), TEMP | |||
ADD TMP0, X15, X15 | |||
ADD TMP1, X14, X14 | |||
ADD TMP2, X13, X13 | |||
ADD TEMP, X12, X12 | |||
// Accumulate key block | |||
VADDUWM A0, K0, A0 | |||
VADDUWM A1, K0, A1 | |||
VADDUWM A2, K0, A2 | |||
VADDUWM B0, K1, B0 | |||
VADDUWM B1, K1, B1 | |||
VADDUWM B2, K1, B2 | |||
VADDUWM C0, K2, C0 | |||
VADDUWM C1, K2, C1 | |||
VADDUWM C2, K2, C2 | |||
VADDUWM D0, K3, D0 | |||
VADDUWM D1, K4, D1 | |||
VADDUWM D2, K5, D2 | |||
// Increment counter | |||
ADD $4, TEMP, TEMP | |||
MOVW TEMP, 0(CNT) | |||
VADDUWM K3, FOUR, K3 | |||
VADDUWM K4, FOUR, K4 | |||
VADDUWM K5, FOUR, K5 | |||
// XOR the input slice (INP) with the keystream, which is stored in GPRs (X0-X3). | |||
// Load input (aligned or not) | |||
MOVWZ 0(INP), TMP0 | |||
MOVWZ 4(INP), TMP1 | |||
MOVWZ 8(INP), TMP2 | |||
MOVWZ 12(INP), TMP3 | |||
// XOR with input | |||
XOR TMP0, X0, X0 | |||
XOR TMP1, X1, X1 | |||
XOR TMP2, X2, X2 | |||
XOR TMP3, X3, X3 | |||
MOVWZ 16(INP), TMP0 | |||
MOVWZ 20(INP), TMP1 | |||
MOVWZ 24(INP), TMP2 | |||
MOVWZ 28(INP), TMP3 | |||
XOR TMP0, X4, X4 | |||
XOR TMP1, X5, X5 | |||
XOR TMP2, X6, X6 | |||
XOR TMP3, X7, X7 | |||
MOVWZ 32(INP), TMP0 | |||
MOVWZ 36(INP), TMP1 | |||
MOVWZ 40(INP), TMP2 | |||
MOVWZ 44(INP), TMP3 | |||
XOR TMP0, X8, X8 | |||
XOR TMP1, X9, X9 | |||
XOR TMP2, X10, X10 | |||
XOR TMP3, X11, X11 | |||
MOVWZ 48(INP), TMP0 | |||
MOVWZ 52(INP), TMP1 | |||
MOVWZ 56(INP), TMP2 | |||
MOVWZ 60(INP), TMP3 | |||
XOR TMP0, X12, X12 | |||
XOR TMP1, X13, X13 | |||
XOR TMP2, X14, X14 | |||
XOR TMP3, X15, X15 | |||
// Store output (aligned or not) | |||
MOVW X0, 0(OUT) | |||
MOVW X1, 4(OUT) | |||
MOVW X2, 8(OUT) | |||
MOVW X3, 12(OUT) | |||
ADD $64, INP, INP // INP points to the end of the slice for the alignment code below | |||
MOVW X4, 16(OUT) | |||
MOVD $16, TMP0 | |||
MOVW X5, 20(OUT) | |||
MOVD $32, TMP1 | |||
MOVW X6, 24(OUT) | |||
MOVD $48, TMP2 | |||
MOVW X7, 28(OUT) | |||
MOVD $64, TMP3 | |||
MOVW X8, 32(OUT) | |||
MOVW X9, 36(OUT) | |||
MOVW X10, 40(OUT) | |||
MOVW X11, 44(OUT) | |||
MOVW X12, 48(OUT) | |||
MOVW X13, 52(OUT) | |||
MOVW X14, 56(OUT) | |||
MOVW X15, 60(OUT) | |||
ADD $64, OUT, OUT | |||
// Load input | |||
LVX (INP)(R0), DD0 | |||
LVX (INP)(TMP0), DD1 | |||
LVX (INP)(TMP1), DD2 | |||
LVX (INP)(TMP2), DD3 | |||
LVX (INP)(TMP3), DD4 | |||
ADD $64, INP, INP | |||
VPERM DD1, DD0, INPPERM, DD0 // Align input | |||
VPERM DD2, DD1, INPPERM, DD1 | |||
VPERM DD3, DD2, INPPERM, DD2 | |||
VPERM DD4, DD3, INPPERM, DD3 | |||
VXOR A0, DD0, A0 // XOR with input | |||
VXOR B0, DD1, B0 | |||
LVX (INP)(TMP0), DD1 // Keep loading input | |||
VXOR C0, DD2, C0 | |||
LVX (INP)(TMP1), DD2 | |||
VXOR D0, DD3, D0 | |||
LVX (INP)(TMP2), DD3 | |||
LVX (INP)(TMP3), DD0 | |||
ADD $64, INP, INP | |||
MOVD $63, TMP3 // 63 is not a typo | |||
VPERM A0, A0, OUTPERM, A0 | |||
VPERM B0, B0, OUTPERM, B0 | |||
VPERM C0, C0, OUTPERM, C0 | |||
VPERM D0, D0, OUTPERM, D0 | |||
VPERM DD1, DD4, INPPERM, DD4 // Align input | |||
VPERM DD2, DD1, INPPERM, DD1 | |||
VPERM DD3, DD2, INPPERM, DD2 | |||
VPERM DD0, DD3, INPPERM, DD3 | |||
VXOR A1, DD4, A1 | |||
VXOR B1, DD1, B1 | |||
LVX (INP)(TMP0), DD1 // Keep loading | |||
VXOR C1, DD2, C1 | |||
LVX (INP)(TMP1), DD2 | |||
VXOR D1, DD3, D1 | |||
LVX (INP)(TMP2), DD3 | |||
// Note that the LVX address is always rounded down to the nearest 16-byte | |||
// boundary, and that it always points to at most 15 bytes beyond the end of | |||
// the slice, so we cannot cross a page boundary. | |||
LVX (INP)(TMP3), DD4 // Redundant in aligned case. | |||
ADD $64, INP, INP | |||
VPERM A1, A1, OUTPERM, A1 // Pre-misalign output | |||
VPERM B1, B1, OUTPERM, B1 | |||
VPERM C1, C1, OUTPERM, C1 | |||
VPERM D1, D1, OUTPERM, D1 | |||
VPERM DD1, DD0, INPPERM, DD0 // Align Input | |||
VPERM DD2, DD1, INPPERM, DD1 | |||
VPERM DD3, DD2, INPPERM, DD2 | |||
VPERM DD4, DD3, INPPERM, DD3 | |||
VXOR A2, DD0, A2 | |||
VXOR B2, DD1, B2 | |||
VXOR C2, DD2, C2 | |||
VXOR D2, DD3, D2 | |||
VPERM A2, A2, OUTPERM, A2 | |||
VPERM B2, B2, OUTPERM, B2 | |||
VPERM C2, C2, OUTPERM, C2 | |||
VPERM D2, D2, OUTPERM, D2 | |||
ANDCC $15, OUT, X1 // Is out aligned? | |||
MOVD OUT, X0 | |||
VSEL A0, B0, OUTMASK, DD0 // Collect pre-misaligned output | |||
VSEL B0, C0, OUTMASK, DD1 | |||
VSEL C0, D0, OUTMASK, DD2 | |||
VSEL D0, A1, OUTMASK, DD3 | |||
VSEL A1, B1, OUTMASK, B0 | |||
VSEL B1, C1, OUTMASK, C0 | |||
VSEL C1, D1, OUTMASK, D0 | |||
VSEL D1, A2, OUTMASK, A1 | |||
VSEL A2, B2, OUTMASK, B1 | |||
VSEL B2, C2, OUTMASK, C1 | |||
VSEL C2, D2, OUTMASK, D1 | |||
STVX DD0, (OUT+TMP0) | |||
STVX DD1, (OUT+TMP1) | |||
STVX DD2, (OUT+TMP2) | |||
ADD $64, OUT, OUT | |||
STVX DD3, (OUT+R0) | |||
STVX B0, (OUT+TMP0) | |||
STVX C0, (OUT+TMP1) | |||
STVX D0, (OUT+TMP2) | |||
ADD $64, OUT, OUT | |||
STVX A1, (OUT+R0) | |||
STVX B1, (OUT+TMP0) | |||
STVX C1, (OUT+TMP1) | |||
STVX D1, (OUT+TMP2) | |||
ADD $64, OUT, OUT | |||
BEQ aligned_vmx | |||
SUB X1, OUT, X2 // in misaligned case edges | |||
MOVD $0, X3 // are written byte-by-byte | |||
unaligned_tail_vmx: | |||
STVEBX D2, (X2+X3) | |||
ADD $1, X3, X3 | |||
CMPW X3, X1 | |||
BNE unaligned_tail_vmx | |||
SUB X1, X0, X2 | |||
unaligned_head_vmx: | |||
STVEBX A0, (X2+X1) | |||
CMPW X1, $15 | |||
ADD $1, X1, X1 | |||
BNE unaligned_head_vmx | |||
CMPU LEN, $255 // done with 256-byte block yet? | |||
BGT loop_outer_vmx | |||
JMP done_vmx | |||
aligned_vmx: | |||
STVX A0, (X0+R0) | |||
CMPU LEN, $255 // done with 256-byte block yet? | |||
BGT loop_outer_vmx | |||
done_vmx: | |||
RET |
@ -0,0 +1,52 @@ | |||
// Copyright 2019 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. | |||
// +build ppc64le,!gccgo,!appengine | |||
package chacha20 | |||
import "encoding/binary" | |||
const ( | |||
bufSize = 256 | |||
haveAsm = true | |||
) | |||
//go:noescape | |||
func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[8]uint32, counter *uint32) | |||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) { | |||
if len(src) >= bufSize { | |||
chaCha20_ctr32_vmx(&dst[0], &src[0], len(src)-len(src)%bufSize, &c.key, &c.counter) | |||
} | |||
if len(src)%bufSize != 0 { | |||
chaCha20_ctr32_vmx(&c.buf[0], &c.buf[0], bufSize, &c.key, &c.counter) | |||
start := len(src) - len(src)%bufSize | |||
ts, td, tb := src[start:], dst[start:], c.buf[:] | |||
// Unroll loop to XOR 32 bytes per iteration. | |||
for i := 0; i < len(ts)-32; i += 32 { | |||
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination | |||
s0 := binary.LittleEndian.Uint64(ts[0:8]) | |||
s1 := binary.LittleEndian.Uint64(ts[8:16]) | |||
s2 := binary.LittleEndian.Uint64(ts[16:24]) | |||
s3 := binary.LittleEndian.Uint64(ts[24:32]) | |||
b0 := binary.LittleEndian.Uint64(tb[0:8]) | |||
b1 := binary.LittleEndian.Uint64(tb[8:16]) | |||
b2 := binary.LittleEndian.Uint64(tb[16:24]) | |||
b3 := binary.LittleEndian.Uint64(tb[24:32]) | |||
binary.LittleEndian.PutUint64(td[0:8], s0^b0) | |||
binary.LittleEndian.PutUint64(td[8:16], s1^b1) | |||
binary.LittleEndian.PutUint64(td[16:24], s2^b2) | |||
binary.LittleEndian.PutUint64(td[24:32], s3^b3) | |||
ts, td, tb = ts[32:], td[32:], tb[32:] | |||
} | |||
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination | |||
for i, v := range ts { | |||
td[i] = tb[i] ^ v | |||
} | |||
c.len = bufSize - (len(src) % bufSize) | |||
} | |||
} |
@ -0,0 +1,68 @@ | |||
// Copyright 2019 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. | |||
// +build ppc64le,!gccgo,!appengine | |||
package poly1305 | |||
//go:noescape | |||
func initialize(state *[7]uint64, key *[32]byte) | |||
//go:noescape | |||
func update(state *[7]uint64, msg []byte) | |||
//go:noescape | |||
func finalize(tag *[TagSize]byte, state *[7]uint64) | |||
// Sum generates an authenticator for m using a one-time key and puts the | |||
// 16-byte result into out. Authenticating two different messages with the same | |||
// key allows an attacker to forge messages at will. | |||
func Sum(out *[16]byte, m []byte, key *[32]byte) { | |||
h := newMAC(key) | |||
h.Write(m) | |||
h.Sum(out) | |||
} | |||
func newMAC(key *[32]byte) (h mac) { | |||
initialize(&h.state, key) | |||
return | |||
} | |||
type mac struct { | |||
state [7]uint64 // := uint64{ h0, h1, h2, r0, r1, pad0, pad1 } | |||
buffer [TagSize]byte | |||
offset int | |||
} | |||
func (h *mac) Write(p []byte) (n int, err error) { | |||
n = len(p) | |||
if h.offset > 0 { | |||
remaining := TagSize - h.offset | |||
if n < remaining { | |||
h.offset += copy(h.buffer[h.offset:], p) | |||
return n, nil | |||
} | |||
copy(h.buffer[h.offset:], p[:remaining]) | |||
p = p[remaining:] | |||
h.offset = 0 | |||
update(&h.state, h.buffer[:]) | |||
} | |||
if nn := len(p) - (len(p) % TagSize); nn > 0 { | |||
update(&h.state, p[:nn]) | |||
p = p[nn:] | |||
} | |||
if len(p) > 0 { | |||
h.offset += copy(h.buffer[h.offset:], p) | |||
} | |||
return n, nil | |||
} | |||
func (h *mac) Sum(out *[16]byte) { | |||
state := h.state | |||
if h.offset > 0 { | |||
update(&state, h.buffer[:h.offset]) | |||
} | |||
finalize(out, &state) | |||
} |
@ -0,0 +1,247 @@ | |||
// Copyright 2019 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. | |||
// +build ppc64le,!gccgo,!appengine | |||
#include "textflag.h" | |||
// This was ported from the amd64 implementation. | |||
#define POLY1305_ADD(msg, h0, h1, h2, t0, t1, t2) \ | |||
MOVD (msg), t0; \ | |||
MOVD 8(msg), t1; \ | |||
MOVD $1, t2; \ | |||
ADDC t0, h0, h0; \ | |||
ADDE t1, h1, h1; \ | |||
ADDE t2, h2; \ | |||
ADD $16, msg | |||
#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \ | |||
MULLD r0, h0, t0; \ | |||
MULLD r0, h1, t4; \ | |||
MULHDU r0, h0, t1; \ | |||
MULHDU r0, h1, t5; \ | |||
ADDC t4, t1, t1; \ | |||
MULLD r0, h2, t2; \ | |||
ADDZE t5; \ | |||
MULHDU r1, h0, t4; \ | |||
MULLD r1, h0, h0; \ | |||
ADD t5, t2, t2; \ | |||
ADDC h0, t1, t1; \ | |||
MULLD h2, r1, t3; \ | |||
ADDZE t4, h0; \ | |||
MULHDU r1, h1, t5; \ | |||
MULLD r1, h1, t4; \ | |||
ADDC t4, t2, t2; \ | |||
ADDE t5, t3, t3; \ | |||
ADDC h0, t2, t2; \ | |||
MOVD $-4, t4; \ | |||
MOVD t0, h0; \ | |||
MOVD t1, h1; \ | |||
ADDZE t3; \ | |||
ANDCC $3, t2, h2; \ | |||
AND t2, t4, t0; \ | |||
ADDC t0, h0, h0; \ | |||
ADDE t3, h1, h1; \ | |||
SLD $62, t3, t4; \ | |||
SRD $2, t2; \ | |||
ADDZE h2; \ | |||
OR t4, t2, t2; \ | |||
SRD $2, t3; \ | |||
ADDC t2, h0, h0; \ | |||
ADDE t3, h1, h1; \ | |||
ADDZE h2 | |||
DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF | |||
DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC | |||
GLOBL ·poly1305Mask<>(SB), RODATA, $16 | |||
// func update(state *[7]uint64, msg []byte) | |||
TEXT ·update(SB), $0-32 | |||
MOVD state+0(FP), R3 | |||
MOVD msg_base+8(FP), R4 | |||
MOVD msg_len+16(FP), R5 | |||
MOVD 0(R3), R8 // h0 | |||
MOVD 8(R3), R9 // h1 | |||
MOVD 16(R3), R10 // h2 | |||
MOVD 24(R3), R11 // r0 | |||
MOVD 32(R3), R12 // r1 | |||
CMP R5, $16 | |||
BLT bytes_between_0_and_15 | |||
loop: | |||
POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22) | |||
multiply: | |||
POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21) | |||
ADD $-16, R5 | |||
CMP R5, $16 | |||
BGE loop | |||
bytes_between_0_and_15: | |||
CMP $0, R5 | |||
BEQ done | |||
MOVD $0, R16 // h0 | |||
MOVD $0, R17 // h1 | |||
flush_buffer: | |||
CMP R5, $8 | |||
BLE just1 | |||
MOVD $8, R21 | |||
SUB R21, R5, R21 | |||
// Greater than 8 -- load the rightmost remaining bytes in msg | |||
// and put into R17 (h1) | |||
MOVD (R4)(R21), R17 | |||
MOVD $16, R22 | |||
// Find the offset to those bytes | |||
SUB R5, R22, R22 | |||
SLD $3, R22 | |||
// Shift to get only the bytes in msg | |||
SRD R22, R17, R17 | |||
// Put 1 at high end | |||
MOVD $1, R23 | |||
SLD $3, R21 | |||
SLD R21, R23, R23 | |||
OR R23, R17, R17 | |||
// Remainder is 8 | |||
MOVD $8, R5 | |||
just1: | |||
CMP R5, $8 | |||
BLT less8 | |||
// Exactly 8 | |||
MOVD (R4), R16 | |||
CMP $0, R17 | |||
// Check if we've already set R17; if not | |||
// set 1 to indicate end of msg. | |||
BNE carry | |||
MOVD $1, R17 | |||
BR carry | |||
less8: | |||
MOVD $0, R16 // h0 | |||
MOVD $0, R22 // shift count | |||
CMP R5, $4 | |||
BLT less4 | |||
MOVWZ (R4), R16 | |||
ADD $4, R4 | |||
ADD $-4, R5 | |||
MOVD $32, R22 | |||
less4: | |||
CMP R5, $2 | |||
BLT less2 | |||
MOVHZ (R4), R21 | |||
SLD R22, R21, R21 | |||
OR R16, R21, R16 | |||
ADD $16, R22 | |||
ADD $-2, R5 | |||
ADD $2, R4 | |||
less2: | |||
CMP $0, R5 | |||
BEQ insert1 | |||
MOVBZ (R4), R21 | |||
SLD R22, R21, R21 | |||
OR R16, R21, R16 | |||
ADD $8, R22 | |||
insert1: | |||
// Insert 1 at end of msg | |||
MOVD $1, R21 | |||
SLD R22, R21, R21 | |||
OR R16, R21, R16 | |||
carry: | |||
// Add new values to h0, h1, h2 | |||
ADDC R16, R8 | |||
ADDE R17, R9 | |||
ADDE $0, R10 | |||
MOVD $16, R5 | |||
ADD R5, R4 | |||
BR multiply | |||
done: | |||
// Save h0, h1, h2 in state | |||
MOVD R8, 0(R3) | |||
MOVD R9, 8(R3) | |||
MOVD R10, 16(R3) | |||
RET | |||
// func initialize(state *[7]uint64, key *[32]byte) | |||
TEXT ·initialize(SB), $0-16 | |||
MOVD state+0(FP), R3 | |||
MOVD key+8(FP), R4 | |||
// state[0...7] is initialized with zero | |||
// Load key | |||
MOVD 0(R4), R5 | |||
MOVD 8(R4), R6 | |||
MOVD 16(R4), R7 | |||
MOVD 24(R4), R8 | |||
// Address of key mask | |||
MOVD $·poly1305Mask<>(SB), R9 | |||
// Save original key in state | |||
MOVD R7, 40(R3) | |||
MOVD R8, 48(R3) | |||
// Get mask | |||
MOVD (R9), R7 | |||
MOVD 8(R9), R8 | |||
// And with key | |||
AND R5, R7, R5 | |||
AND R6, R8, R6 | |||
// Save masked key in state | |||
MOVD R5, 24(R3) | |||
MOVD R6, 32(R3) | |||
RET | |||
// func finalize(tag *[TagSize]byte, state *[7]uint64) | |||
TEXT ·finalize(SB), $0-16 | |||
MOVD tag+0(FP), R3 | |||
MOVD state+8(FP), R4 | |||
// Get h0, h1, h2 from state | |||
MOVD 0(R4), R5 | |||
MOVD 8(R4), R6 | |||
MOVD 16(R4), R7 | |||
// Save h0, h1 | |||
MOVD R5, R8 | |||
MOVD R6, R9 | |||
MOVD $3, R20 | |||
MOVD $-1, R21 | |||
SUBC $-5, R5 | |||
SUBE R21, R6 | |||
SUBE R20, R7 | |||
MOVD $0, R21 | |||
SUBZE R21 | |||
// Check for carry | |||
CMP $0, R21 | |||
ISEL $2, R5, R8, R5 | |||
ISEL $2, R6, R9, R6 | |||
MOVD 40(R4), R8 | |||
MOVD 48(R4), R9 | |||
ADDC R8, R5 | |||
ADDE R9, R6 | |||
MOVD R5, 0(R3) | |||
MOVD R6, 8(R3) | |||
RET |
@ -0,0 +1,139 @@ | |||
// Copyright 2011 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. | |||
package ssh | |||
import ( | |||
"encoding/asn1" | |||
"errors" | |||
) | |||
var krb5OID []byte | |||
func init() { | |||
krb5OID, _ = asn1.Marshal(krb5Mesh) | |||
} | |||
// GSSAPIClient provides the API to plug-in GSSAPI authentication for client logins. | |||
type GSSAPIClient interface { | |||
// InitSecContext initiates the establishment of a security context for GSS-API between the | |||
// ssh client and ssh server. Initially the token parameter should be specified as nil. | |||
// The routine may return a outputToken which should be transferred to | |||
// the ssh server, where the ssh server will present it to | |||
// AcceptSecContext. If no token need be sent, InitSecContext will indicate this by setting | |||
// needContinue to false. To complete the context | |||
// establishment, one or more reply tokens may be required from the ssh | |||
// server;if so, InitSecContext will return a needContinue which is true. | |||
// In this case, InitSecContext should be called again when the | |||
// reply token is received from the ssh server, passing the reply | |||
// token to InitSecContext via the token parameters. | |||
// See RFC 2743 section 2.2.1 and RFC 4462 section 3.4. | |||
InitSecContext(target string, token []byte, isGSSDelegCreds bool) (outputToken []byte, needContinue bool, err error) | |||
// GetMIC generates a cryptographic MIC for the SSH2 message, and places | |||
// the MIC in a token for transfer to the ssh server. | |||
// The contents of the MIC field are obtained by calling GSS_GetMIC() | |||
// over the following, using the GSS-API context that was just | |||
// established: | |||
// string session identifier | |||
// byte SSH_MSG_USERAUTH_REQUEST | |||
// string user name | |||
// string service | |||
// string "gssapi-with-mic" | |||
// See RFC 2743 section 2.3.1 and RFC 4462 3.5. | |||
GetMIC(micFiled []byte) ([]byte, error) | |||
// Whenever possible, it should be possible for | |||
// DeleteSecContext() calls to be successfully processed even | |||
// if other calls cannot succeed, thereby enabling context-related | |||
// resources to be released. | |||
// In addition to deleting established security contexts, | |||
// gss_delete_sec_context must also be able to delete "half-built" | |||
// security contexts resulting from an incomplete sequence of | |||
// InitSecContext()/AcceptSecContext() calls. | |||
// See RFC 2743 section 2.2.3. | |||
DeleteSecContext() error | |||
} | |||
// GSSAPIServer provides the API to plug in GSSAPI authentication for server logins. | |||
type GSSAPIServer interface { | |||
// AcceptSecContext allows a remotely initiated security context between the application | |||
// and a remote peer to be established by the ssh client. The routine may return a | |||
// outputToken which should be transferred to the ssh client, | |||
// where the ssh client will present it to InitSecContext. | |||
// If no token need be sent, AcceptSecContext will indicate this | |||
// by setting the needContinue to false. To | |||
// complete the context establishment, one or more reply tokens may be | |||
// required from the ssh client. if so, AcceptSecContext | |||
// will return a needContinue which is true, in which case it | |||
// should be called again when the reply token is received from the ssh | |||
// client, passing the token to AcceptSecContext via the | |||
// token parameters. | |||
// The srcName return value is the authenticated username. | |||
// See RFC 2743 section 2.2.2 and RFC 4462 section 3.4. | |||
AcceptSecContext(token []byte) (outputToken []byte, srcName string, needContinue bool, err error) | |||
// VerifyMIC verifies that a cryptographic MIC, contained in the token parameter, | |||
// fits the supplied message is received from the ssh client. | |||
// See RFC 2743 section 2.3.2. | |||
VerifyMIC(micField []byte, micToken []byte) error | |||
// Whenever possible, it should be possible for | |||
// DeleteSecContext() calls to be successfully processed even | |||
// if other calls cannot succeed, thereby enabling context-related | |||
// resources to be released. | |||
// In addition to deleting established security contexts, | |||
// gss_delete_sec_context must also be able to delete "half-built" | |||
// security contexts resulting from an incomplete sequence of | |||
// InitSecContext()/AcceptSecContext() calls. | |||
// See RFC 2743 section 2.2.3. | |||
DeleteSecContext() error | |||
} | |||
var ( | |||
// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication, | |||
// so we also support the krb5 mechanism only. | |||
// See RFC 1964 section 1. | |||
krb5Mesh = asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2} | |||
) | |||
// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST | |||
// See RFC 4462 section 3.2. | |||
type userAuthRequestGSSAPI struct { | |||
N uint32 | |||
OIDS []asn1.ObjectIdentifier | |||
} | |||
func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) { | |||
n, rest, ok := parseUint32(payload) | |||
if !ok { | |||
return nil, errors.New("parse uint32 failed") | |||
} | |||
s := &userAuthRequestGSSAPI{ | |||
N: n, | |||
OIDS: make([]asn1.ObjectIdentifier, n), | |||
} | |||
for i := 0; i < int(n); i++ { | |||
var ( | |||
desiredMech []byte | |||
err error | |||
) | |||
desiredMech, rest, ok = parseString(rest) | |||
if !ok { | |||
return nil, errors.New("parse string failed") | |||
} | |||
if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil { | |||
return nil, err | |||
} | |||
} | |||
return s, nil | |||
} | |||
// See RFC 4462 section 3.6. | |||
func buildMIC(sessionID string, username string, service string, authMethod string) []byte { | |||
out := make([]byte, 0, 0) | |||
out = appendString(out, sessionID) | |||
out = append(out, msgUserAuthRequest) | |||
out = appendString(out, username) | |||
out = appendString(out, service) | |||
out = appendString(out, authMethod) | |||
return out | |||
} |
@ -1,147 +0,0 @@ | |||
// Copyright 2015 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. | |||
// +build !go1.7 | |||
package ctxhttp // import "golang.org/x/net/context/ctxhttp" | |||
import ( | |||
"io" | |||
"net/http" | |||
"net/url" | |||
"strings" | |||
"golang.org/x/net/context" | |||
) | |||
func nop() {} | |||
var ( | |||
testHookContextDoneBeforeHeaders = nop | |||
testHookDoReturned = nop | |||
testHookDidBodyClose = nop | |||
) | |||
// Do sends an HTTP request with the provided http.Client and returns an HTTP response. | |||
// If the client is nil, http.DefaultClient is used. | |||
// If the context is canceled or times out, ctx.Err() will be returned. | |||
func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { | |||
if client == nil { | |||
client = http.DefaultClient | |||
} | |||
// TODO(djd): Respect any existing value of req.Cancel. | |||
cancel := make(chan struct{}) | |||
req.Cancel = cancel | |||
type responseAndError struct { | |||
resp *http.Response | |||
err error | |||
} | |||
result := make(chan responseAndError, 1) | |||
// Make local copies of test hooks closed over by goroutines below. | |||
// Prevents data races in tests. | |||
testHookDoReturned := testHookDoReturned | |||
testHookDidBodyClose := testHookDidBodyClose | |||
go func() { | |||
resp, err := client.Do(req) | |||
testHookDoReturned() | |||
result <- responseAndError{resp, err} | |||
}() | |||
var resp *http.Response | |||
select { | |||
case <-ctx.Done(): | |||
testHookContextDoneBeforeHeaders() | |||
close(cancel) | |||
// Clean up after the goroutine calling client.Do: | |||
go func() { | |||
if r := <-result; r.resp != nil { | |||
testHookDidBodyClose() | |||
r.resp.Body.Close() | |||
} | |||
}() | |||
return nil, ctx.Err() | |||
case r := <-result: | |||
var err error | |||
resp, err = r.resp, r.err | |||
if err != nil { | |||
return resp, err | |||
} | |||
} | |||
c := make(chan struct{}) | |||
go func() { | |||
select { | |||
case <-ctx.Done(): | |||
close(cancel) | |||
case <-c: | |||
// The response's Body is closed. | |||
} | |||
}() | |||
resp.Body = ¬ifyingReader{resp.Body, c} | |||
return resp, nil | |||
} | |||
// Get issues a GET request via the Do function. | |||
func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) { | |||
req, err := http.NewRequest("GET", url, nil) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return Do(ctx, client, req) | |||
} | |||
// Head issues a HEAD request via the Do function. | |||
func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) { | |||
req, err := http.NewRequest("HEAD", url, nil) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return Do(ctx, client, req) | |||
} | |||
// Post issues a POST request via the Do function. | |||
func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) { | |||
req, err := http.NewRequest("POST", url, body) | |||
if err != nil { | |||
return nil, err | |||
} | |||
req.Header.Set("Content-Type", bodyType) | |||
return Do(ctx, client, req) | |||
} | |||
// PostForm issues a POST request via the Do function. | |||
func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) { | |||
return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) | |||
} | |||
// notifyingReader is an io.ReadCloser that closes the notify channel after | |||
// Close is called or a Read fails on the underlying ReadCloser. | |||
type notifyingReader struct { | |||
io.ReadCloser | |||
notify chan<- struct{} | |||
} | |||
func (r *notifyingReader) Read(p []byte) (int, error) { | |||
n, err := r.ReadCloser.Read(p) | |||
if err != nil && r.notify != nil { | |||
close(r.notify) | |||
r.notify = nil | |||
} | |||
return n, err | |||
} | |||
func (r *notifyingReader) Close() error { | |||
err := r.ReadCloser.Close() | |||
if r.notify != nil { | |||
close(r.notify) | |||
r.notify = nil | |||
} | |||
return err | |||
} |
@ -0,0 +1,734 @@ | |||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
// Copyright 2016 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. | |||
// +build go1.10 | |||
// Package idna implements IDNA2008 using the compatibility processing | |||
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to | |||
// deal with the transition from IDNA2003. | |||
// | |||
// IDNA2008 (Internationalized Domain Names for Applications), is defined in RFC | |||
// 5890, RFC 5891, RFC 5892, RFC 5893 and RFC 5894. | |||
// UTS #46 is defined in https://www.unicode.org/reports/tr46. | |||
// See https://unicode.org/cldr/utility/idna.jsp for a visualization of the | |||
// differences between these two standards. | |||
package idna // import "golang.org/x/net/idna" | |||
import ( | |||
"fmt" | |||
"strings" | |||
"unicode/utf8" | |||
"golang.org/x/text/secure/bidirule" | |||
"golang.org/x/text/unicode/bidi" | |||
"golang.org/x/text/unicode/norm" | |||
) | |||
// NOTE: Unlike common practice in Go APIs, the functions will return a | |||
// sanitized domain name in case of errors. Browsers sometimes use a partially | |||
// evaluated string as lookup. | |||
// TODO: the current error handling is, in my opinion, the least opinionated. | |||
// Other strategies are also viable, though: | |||
// Option 1) Return an empty string in case of error, but allow the user to | |||
// specify explicitly which errors to ignore. | |||
// Option 2) Return the partially evaluated string if it is itself a valid | |||
// string, otherwise return the empty string in case of error. | |||
// Option 3) Option 1 and 2. | |||
// Option 4) Always return an empty string for now and implement Option 1 as | |||
// needed, and document that the return string may not be empty in case of | |||
// error in the future. | |||
// I think Option 1 is best, but it is quite opinionated. | |||
// ToASCII is a wrapper for Punycode.ToASCII. | |||
func ToASCII(s string) (string, error) { | |||
return Punycode.process(s, true) | |||
} | |||
// ToUnicode is a wrapper for Punycode.ToUnicode. | |||
func ToUnicode(s string) (string, error) { | |||
return Punycode.process(s, false) | |||
} | |||
// An Option configures a Profile at creation time. | |||
type Option func(*options) | |||
// Transitional sets a Profile to use the Transitional mapping as defined in UTS | |||
// #46. This will cause, for example, "ß" to be mapped to "ss". Using the | |||
// transitional mapping provides a compromise between IDNA2003 and IDNA2008 | |||
// compatibility. It is used by most browsers when resolving domain names. This | |||
// option is only meaningful if combined with MapForLookup. | |||
func Transitional(transitional bool) Option { | |||
return func(o *options) { o.transitional = true } | |||
} | |||
// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts | |||
// are longer than allowed by the RFC. | |||
func VerifyDNSLength(verify bool) Option { | |||
return func(o *options) { o.verifyDNSLength = verify } | |||
} | |||
// RemoveLeadingDots removes leading label separators. Leading runes that map to | |||
// dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well. | |||
// | |||
// This is the behavior suggested by the UTS #46 and is adopted by some | |||
// browsers. | |||
func RemoveLeadingDots(remove bool) Option { | |||
return func(o *options) { o.removeLeadingDots = remove } | |||
} | |||
// ValidateLabels sets whether to check the mandatory label validation criteria | |||
// as defined in Section 5.4 of RFC 5891. This includes testing for correct use | |||
// of hyphens ('-'), normalization, validity of runes, and the context rules. | |||
func ValidateLabels(enable bool) Option { | |||
return func(o *options) { | |||
// Don't override existing mappings, but set one that at least checks | |||
// normalization if it is not set. | |||
if o.mapping == nil && enable { | |||
o.mapping = normalize | |||
} | |||
o.trie = trie | |||
o.validateLabels = enable | |||
o.fromPuny = validateFromPunycode | |||
} | |||
} | |||
// StrictDomainName limits the set of permissible ASCII characters to those | |||
// allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the | |||
// hyphen). This is set by default for MapForLookup and ValidateForRegistration. | |||
// | |||
// This option is useful, for instance, for browsers that allow characters | |||
// outside this range, for example a '_' (U+005F LOW LINE). See | |||
// http://www.rfc-editor.org/std/std3.txt for more details This option | |||
// corresponds to the UseSTD3ASCIIRules option in UTS #46. | |||
func StrictDomainName(use bool) Option { | |||
return func(o *options) { | |||
o.trie = trie | |||
o.useSTD3Rules = use | |||
o.fromPuny = validateFromPunycode | |||
} | |||
} | |||
// NOTE: the following options pull in tables. The tables should not be linked | |||
// in as long as the options are not used. | |||
// BidiRule enables the Bidi rule as defined in RFC 5893. Any application | |||
// that relies on proper validation of labels should include this rule. | |||
func BidiRule() Option { | |||
return func(o *options) { o.bidirule = bidirule.ValidString } | |||
} | |||
// ValidateForRegistration sets validation options to verify that a given IDN is | |||
// properly formatted for registration as defined by Section 4 of RFC 5891. | |||
func ValidateForRegistration() Option { | |||
return func(o *options) { | |||
o.mapping = validateRegistration | |||
StrictDomainName(true)(o) | |||
ValidateLabels(true)(o) | |||
VerifyDNSLength(true)(o) | |||
BidiRule()(o) | |||
} | |||
} | |||
// MapForLookup sets validation and mapping options such that a given IDN is | |||
// transformed for domain name lookup according to the requirements set out in | |||
// Section 5 of RFC 5891. The mappings follow the recommendations of RFC 5894, | |||
// RFC 5895 and UTS 46. It does not add the Bidi Rule. Use the BidiRule option | |||
// to add this check. | |||
// | |||
// The mappings include normalization and mapping case, width and other | |||
// compatibility mappings. | |||
func MapForLookup() Option { | |||
return func(o *options) { | |||
o.mapping = validateAndMap | |||
StrictDomainName(true)(o) | |||
ValidateLabels(true)(o) | |||
} | |||
} | |||
type options struct { | |||
transitional bool | |||
useSTD3Rules bool | |||
validateLabels bool | |||
verifyDNSLength bool | |||
removeLeadingDots bool | |||
trie *idnaTrie | |||
// fromPuny calls validation rules when converting A-labels to U-labels. | |||
fromPuny func(p *Profile, s string) error | |||
// mapping implements a validation and mapping step as defined in RFC 5895 | |||
// or UTS 46, tailored to, for example, domain registration or lookup. | |||
mapping func(p *Profile, s string) (mapped string, isBidi bool, err error) | |||
// bidirule, if specified, checks whether s conforms to the Bidi Rule | |||
// defined in RFC 5893. | |||
bidirule func(s string) bool | |||
} | |||
// A Profile defines the configuration of an IDNA mapper. | |||
type Profile struct { | |||
options | |||
} | |||
func apply(o *options, opts []Option) { | |||
for _, f := range opts { | |||
f(o) | |||
} | |||
} | |||
// New creates a new Profile. | |||
// | |||
// With no options, the returned Profile is the most permissive and equals the | |||
// Punycode Profile. Options can be passed to further restrict the Profile. The | |||
// MapForLookup and ValidateForRegistration options set a collection of options, | |||
// for lookup and registration purposes respectively, which can be tailored by | |||
// adding more fine-grained options, where later options override earlier | |||
// options. | |||
func New(o ...Option) *Profile { | |||
p := &Profile{} | |||
apply(&p.options, o) | |||
return p | |||
} | |||
// ToASCII converts a domain or domain label to its ASCII form. For example, | |||
// ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and | |||
// ToASCII("golang") is "golang". If an error is encountered it will return | |||
// an error and a (partially) processed result. | |||
func (p *Profile) ToASCII(s string) (string, error) { | |||
return p.process(s, true) | |||
} | |||
// ToUnicode converts a domain or domain label to its Unicode form. For example, | |||
// ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and | |||
// ToUnicode("golang") is "golang". If an error is encountered it will return | |||
// an error and a (partially) processed result. | |||
func (p *Profile) ToUnicode(s string) (string, error) { | |||
pp := *p | |||
pp.transitional = false | |||
return pp.process(s, false) | |||
} | |||
// String reports a string with a description of the profile for debugging | |||
// purposes. The string format may change with different versions. | |||
func (p *Profile) String() string { | |||
s := "" | |||
if p.transitional { | |||
s = "Transitional" | |||
} else { | |||
s = "NonTransitional" | |||
} | |||
if p.useSTD3Rules { | |||
s += ":UseSTD3Rules" | |||
} | |||
if p.validateLabels { | |||
s += ":ValidateLabels" | |||
} | |||
if p.verifyDNSLength { | |||
s += ":VerifyDNSLength" | |||
} | |||
return s | |||
} | |||
var ( | |||
// Punycode is a Profile that does raw punycode processing with a minimum | |||
// of validation. | |||
Punycode *Profile = punycode | |||
// Lookup is the recommended profile for looking up domain names, according | |||
// to Section 5 of RFC 5891. The exact configuration of this profile may | |||
// change over time. | |||
Lookup *Profile = lookup | |||
// Display is the recommended profile for displaying domain names. | |||
// The configuration of this profile may change over time. | |||
Display *Profile = display | |||
// Registration is the recommended profile for checking whether a given | |||
// IDN is valid for registration, according to Section 4 of RFC 5891. | |||
Registration *Profile = registration | |||
punycode = &Profile{} | |||
lookup = &Profile{options{ | |||
transitional: true, | |||
useSTD3Rules: true, | |||
validateLabels: true, | |||
trie: trie, | |||
fromPuny: validateFromPunycode, | |||
mapping: validateAndMap, | |||
bidirule: bidirule.ValidString, | |||
}} | |||
display = &Profile{options{ | |||
useSTD3Rules: true, | |||
validateLabels: true, | |||
trie: trie, | |||
fromPuny: validateFromPunycode, | |||
mapping: validateAndMap, | |||
bidirule: bidirule.ValidString, | |||
}} | |||
registration = &Profile{options{ | |||
useSTD3Rules: true, | |||
validateLabels: true, | |||
verifyDNSLength: true, | |||
trie: trie, | |||
fromPuny: validateFromPunycode, | |||
mapping: validateRegistration, | |||
bidirule: bidirule.ValidString, | |||
}} | |||
// TODO: profiles | |||
// Register: recommended for approving domain names: don't do any mappings | |||
// but rather reject on invalid input. Bundle or block deviation characters. | |||
) | |||
type labelError struct{ label, code_ string } | |||
func (e labelError) code() string { return e.code_ } | |||
func (e labelError) Error() string { | |||
return fmt.Sprintf("idna: invalid label %q", e.label) | |||
} | |||
type runeError rune | |||
func (e runeError) code() string { return "P1" } | |||
func (e runeError) Error() string { | |||
return fmt.Sprintf("idna: disallowed rune %U", e) | |||
} | |||
// process implements the algorithm described in section 4 of UTS #46, | |||
// see https://www.unicode.org/reports/tr46. | |||
func (p *Profile) process(s string, toASCII bool) (string, error) { | |||
var err error | |||
var isBidi bool | |||
if p.mapping != nil { | |||
s, isBidi, err = p.mapping(p, s) | |||
} | |||
// Remove leading empty labels. | |||
if p.removeLeadingDots { | |||
for ; len(s) > 0 && s[0] == '.'; s = s[1:] { | |||
} | |||
} | |||
// TODO: allow for a quick check of the tables data. | |||
// It seems like we should only create this error on ToASCII, but the | |||
// UTS 46 conformance tests suggests we should always check this. | |||
if err == nil && p.verifyDNSLength && s == "" { | |||
err = &labelError{s, "A4"} | |||
} | |||
labels := labelIter{orig: s} | |||
for ; !labels.done(); labels.next() { | |||
label := labels.label() | |||
if label == "" { | |||
// Empty labels are not okay. The label iterator skips the last | |||
// label if it is empty. | |||
if err == nil && p.verifyDNSLength { | |||
err = &labelError{s, "A4"} | |||
} | |||
continue | |||
} | |||
if strings.HasPrefix(label, acePrefix) { | |||
u, err2 := decode(label[len(acePrefix):]) | |||
if err2 != nil { | |||
if err == nil { | |||
err = err2 | |||
} | |||
// Spec says keep the old label. | |||
continue | |||
} | |||
isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight | |||
labels.set(u) | |||
if err == nil && p.validateLabels { | |||
err = p.fromPuny(p, u) | |||
} | |||
if err == nil { | |||
// This should be called on NonTransitional, according to the | |||
// spec, but that currently does not have any effect. Use the | |||
// original profile to preserve options. | |||
err = p.validateLabel(u) | |||
} | |||
} else if err == nil { | |||
err = p.validateLabel(label) | |||
} | |||
} | |||
if isBidi && p.bidirule != nil && err == nil { | |||
for labels.reset(); !labels.done(); labels.next() { | |||
if !p.bidirule(labels.label()) { | |||
err = &labelError{s, "B"} | |||
break | |||
} | |||
} | |||
} | |||
if toASCII { | |||
for labels.reset(); !labels.done(); labels.next() { | |||
label := labels.label() | |||
if !ascii(label) { | |||
a, err2 := encode(acePrefix, label) | |||
if err == nil { | |||
err = err2 | |||
} | |||
label = a | |||
labels.set(a) | |||
} | |||
n := len(label) | |||
if p.verifyDNSLength && err == nil && (n == 0 || n > 63) { | |||
err = &labelError{label, "A4"} | |||
} | |||
} | |||
} | |||
s = labels.result() | |||
if toASCII && p.verifyDNSLength && err == nil { | |||
// Compute the length of the domain name minus the root label and its dot. | |||
n := len(s) | |||
if n > 0 && s[n-1] == '.' { | |||
n-- | |||
} | |||
if len(s) < 1 || n > 253 { | |||
err = &labelError{s, "A4"} | |||
} | |||
} | |||
return s, err | |||
} | |||
func normalize(p *Profile, s string) (mapped string, isBidi bool, err error) { | |||
// TODO: consider first doing a quick check to see if any of these checks | |||
// need to be done. This will make it slower in the general case, but | |||
// faster in the common case. | |||
mapped = norm.NFC.String(s) | |||
isBidi = bidirule.DirectionString(mapped) == bidi.RightToLeft | |||
return mapped, isBidi, nil | |||
} | |||
func validateRegistration(p *Profile, s string) (idem string, bidi bool, err error) { | |||
// TODO: filter need for normalization in loop below. | |||
if !norm.NFC.IsNormalString(s) { | |||
return s, false, &labelError{s, "V1"} | |||
} | |||
for i := 0; i < len(s); { | |||
v, sz := trie.lookupString(s[i:]) | |||
if sz == 0 { | |||
return s, bidi, runeError(utf8.RuneError) | |||
} | |||
bidi = bidi || info(v).isBidi(s[i:]) | |||
// Copy bytes not copied so far. | |||
switch p.simplify(info(v).category()) { | |||
// TODO: handle the NV8 defined in the Unicode idna data set to allow | |||
// for strict conformance to IDNA2008. | |||
case valid, deviation: | |||
case disallowed, mapped, unknown, ignored: | |||
r, _ := utf8.DecodeRuneInString(s[i:]) | |||
return s, bidi, runeError(r) | |||
} | |||
i += sz | |||
} | |||
return s, bidi, nil | |||
} | |||
func (c info) isBidi(s string) bool { | |||
if !c.isMapped() { | |||
return c&attributesMask == rtl | |||
} | |||
// TODO: also store bidi info for mapped data. This is possible, but a bit | |||
// cumbersome and not for the common case. | |||
p, _ := bidi.LookupString(s) | |||
switch p.Class() { | |||
case bidi.R, bidi.AL, bidi.AN: | |||
return true | |||
} | |||
return false | |||
} | |||
func validateAndMap(p *Profile, s string) (vm string, bidi bool, err error) { | |||
var ( | |||
b []byte | |||
k int | |||
) | |||
// combinedInfoBits contains the or-ed bits of all runes. We use this | |||
// to derive the mayNeedNorm bit later. This may trigger normalization | |||
// overeagerly, but it will not do so in the common case. The end result | |||
// is another 10% saving on BenchmarkProfile for the common case. | |||
var combinedInfoBits info | |||
for i := 0; i < len(s); { | |||
v, sz := trie.lookupString(s[i:]) | |||
if sz == 0 { | |||
b = append(b, s[k:i]...) | |||
b = append(b, "\ufffd"...) | |||
k = len(s) | |||
if err == nil { | |||
err = runeError(utf8.RuneError) | |||
} | |||
break | |||
} | |||
combinedInfoBits |= info(v) | |||
bidi = bidi || info(v).isBidi(s[i:]) | |||
start := i | |||
i += sz | |||
// Copy bytes not copied so far. | |||
switch p.simplify(info(v).category()) { | |||
case valid: | |||
continue | |||
case disallowed: | |||
if err == nil { | |||
r, _ := utf8.DecodeRuneInString(s[start:]) | |||
err = runeError(r) | |||
} | |||
continue | |||
case mapped, deviation: | |||
b = append(b, s[k:start]...) | |||
b = info(v).appendMapping(b, s[start:i]) | |||
case ignored: | |||
b = append(b, s[k:start]...) | |||
// drop the rune | |||
case unknown: | |||
b = append(b, s[k:start]...) | |||
b = append(b, "\ufffd"...) | |||
} | |||
k = i | |||
} | |||
if k == 0 { | |||
// No changes so far. | |||
if combinedInfoBits&mayNeedNorm != 0 { | |||
s = norm.NFC.String(s) | |||
} | |||
} else { | |||
b = append(b, s[k:]...) | |||
if norm.NFC.QuickSpan(b) != len(b) { | |||
b = norm.NFC.Bytes(b) | |||
} | |||
// TODO: the punycode converters require strings as input. | |||
s = string(b) | |||
} | |||
return s, bidi, err | |||
} | |||
// A labelIter allows iterating over domain name labels. | |||
type labelIter struct { | |||
orig string | |||
slice []string | |||
curStart int | |||
curEnd int | |||
i int | |||
} | |||
func (l *labelIter) reset() { | |||
l.curStart = 0 | |||
l.curEnd = 0 | |||
l.i = 0 | |||
} | |||
func (l *labelIter) done() bool { | |||
return l.curStart >= len(l.orig) | |||
} | |||
func (l *labelIter) result() string { | |||
if l.slice != nil { | |||
return strings.Join(l.slice, ".") | |||
} | |||
return l.orig | |||
} | |||
func (l *labelIter) label() string { | |||
if l.slice != nil { | |||
return l.slice[l.i] | |||
} | |||
p := strings.IndexByte(l.orig[l.curStart:], '.') | |||
l.curEnd = l.curStart + p | |||
if p == -1 { | |||
l.curEnd = len(l.orig) | |||
} | |||
return l.orig[l.curStart:l.curEnd] | |||
} | |||
// next sets the value to the next label. It skips the last label if it is empty. | |||
func (l *labelIter) next() { | |||
l.i++ | |||
if l.slice != nil { | |||
if l.i >= len(l.slice) || l.i == len(l.slice)-1 && l.slice[l.i] == "" { | |||
l.curStart = len(l.orig) | |||
} | |||
} else { | |||
l.curStart = l.curEnd + 1 | |||
if l.curStart == len(l.orig)-1 && l.orig[l.curStart] == '.' { | |||
l.curStart = len(l.orig) | |||
} | |||
} | |||
} | |||
func (l *labelIter) set(s string) { | |||
if l.slice == nil { | |||
l.slice = strings.Split(l.orig, ".") | |||
} | |||
l.slice[l.i] = s | |||
} | |||
// acePrefix is the ASCII Compatible Encoding prefix. | |||
const acePrefix = "xn--" | |||
func (p *Profile) simplify(cat category) category { | |||
switch cat { | |||
case disallowedSTD3Mapped: | |||
if p.useSTD3Rules { | |||
cat = disallowed | |||
} else { | |||
cat = mapped | |||
} | |||
case disallowedSTD3Valid: | |||
if p.useSTD3Rules { | |||
cat = disallowed | |||
} else { | |||
cat = valid | |||
} | |||
case deviation: | |||
if !p.transitional { | |||
cat = valid | |||
} | |||
case validNV8, validXV8: | |||
// TODO: handle V2008 | |||
cat = valid | |||
} | |||
return cat | |||
} | |||
func validateFromPunycode(p *Profile, s string) error { | |||
if !norm.NFC.IsNormalString(s) { | |||
return &labelError{s, "V1"} | |||
} | |||
// TODO: detect whether string may have to be normalized in the following | |||
// loop. | |||
for i := 0; i < len(s); { | |||
v, sz := trie.lookupString(s[i:]) | |||
if sz == 0 { | |||
return runeError(utf8.RuneError) | |||
} | |||
if c := p.simplify(info(v).category()); c != valid && c != deviation { | |||
return &labelError{s, "V6"} | |||
} | |||
i += sz | |||
} | |||
return nil | |||
} | |||
const ( | |||
zwnj = "\u200c" | |||
zwj = "\u200d" | |||
) | |||
type joinState int8 | |||
const ( | |||
stateStart joinState = iota | |||
stateVirama | |||
stateBefore | |||
stateBeforeVirama | |||
stateAfter | |||
stateFAIL | |||
) | |||
var joinStates = [][numJoinTypes]joinState{ | |||
stateStart: { | |||
joiningL: stateBefore, | |||
joiningD: stateBefore, | |||
joinZWNJ: stateFAIL, | |||
joinZWJ: stateFAIL, | |||
joinVirama: stateVirama, | |||
}, | |||
stateVirama: { | |||
joiningL: stateBefore, | |||
joiningD: stateBefore, | |||
}, | |||
stateBefore: { | |||
joiningL: stateBefore, | |||
joiningD: stateBefore, | |||
joiningT: stateBefore, | |||
joinZWNJ: stateAfter, | |||
joinZWJ: stateFAIL, | |||
joinVirama: stateBeforeVirama, | |||
}, | |||
stateBeforeVirama: { | |||
joiningL: stateBefore, | |||
joiningD: stateBefore, | |||
joiningT: stateBefore, | |||
}, | |||
stateAfter: { | |||
joiningL: stateFAIL, | |||
joiningD: stateBefore, | |||
joiningT: stateAfter, | |||
joiningR: stateStart, | |||
joinZWNJ: stateFAIL, | |||
joinZWJ: stateFAIL, | |||
joinVirama: stateAfter, // no-op as we can't accept joiners here | |||
}, | |||
stateFAIL: { | |||
0: stateFAIL, | |||
joiningL: stateFAIL, | |||
joiningD: stateFAIL, | |||
joiningT: stateFAIL, | |||
joiningR: stateFAIL, | |||
joinZWNJ: stateFAIL, | |||
joinZWJ: stateFAIL, | |||
joinVirama: stateFAIL, | |||
}, | |||
} | |||
// validateLabel validates the criteria from Section 4.1. Item 1, 4, and 6 are | |||
// already implicitly satisfied by the overall implementation. | |||
func (p *Profile) validateLabel(s string) (err error) { | |||
if s == "" { | |||
if p.verifyDNSLength { | |||
return &labelError{s, "A4"} | |||
} | |||
return nil | |||
} | |||
if !p.validateLabels { | |||
return nil | |||
} | |||
trie := p.trie // p.validateLabels is only set if trie is set. | |||
if len(s) > 4 && s[2] == '-' && s[3] == '-' { | |||
return &labelError{s, "V2"} | |||
} | |||
if s[0] == '-' || s[len(s)-1] == '-' { | |||
return &labelError{s, "V3"} | |||
} | |||
// TODO: merge the use of this in the trie. | |||
v, sz := trie.lookupString(s) | |||
x := info(v) | |||
if x.isModifier() { | |||
return &labelError{s, "V5"} | |||
} | |||
// Quickly return in the absence of zero-width (non) joiners. | |||
if strings.Index(s, zwj) == -1 && strings.Index(s, zwnj) == -1 { | |||
return nil | |||
} | |||
st := stateStart | |||
for i := 0; ; { | |||
jt := x.joinType() | |||
if s[i:i+sz] == zwj { | |||
jt = joinZWJ | |||
} else if s[i:i+sz] == zwnj { | |||
jt = joinZWNJ | |||
} | |||
st = joinStates[st][jt] | |||
if x.isViramaModifier() { | |||
st = joinStates[st][joinVirama] | |||
} | |||
if i += sz; i == len(s) { | |||
break | |||
} | |||
v, sz = trie.lookupString(s[i:]) | |||
x = info(v) | |||
} | |||
if st == stateFAIL || st == stateAfter { | |||
return &labelError{s, "C"} | |||
} | |||
return nil | |||
} | |||
func ascii(s string) bool { | |||
for i := 0; i < len(s); i++ { | |||
if s[i] >= utf8.RuneSelf { | |||
return false | |||
} | |||
} | |||
return true | |||
} |
@ -0,0 +1,682 @@ | |||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
// Copyright 2016 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. | |||
// +build !go1.10 | |||
// Package idna implements IDNA2008 using the compatibility processing | |||
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to | |||
// deal with the transition from IDNA2003. | |||
// | |||
// IDNA2008 (Internationalized Domain Names for Applications), is defined in RFC | |||
// 5890, RFC 5891, RFC 5892, RFC 5893 and RFC 5894. | |||
// UTS #46 is defined in https://www.unicode.org/reports/tr46. | |||
// See https://unicode.org/cldr/utility/idna.jsp for a visualization of the | |||
// differences between these two standards. | |||
package idna // import "golang.org/x/net/idna" | |||
import ( | |||
"fmt" | |||
"strings" | |||
"unicode/utf8" | |||
"golang.org/x/text/secure/bidirule" | |||
"golang.org/x/text/unicode/norm" | |||
) | |||
// NOTE: Unlike common practice in Go APIs, the functions will return a | |||
// sanitized domain name in case of errors. Browsers sometimes use a partially | |||
// evaluated string as lookup. | |||
// TODO: the current error handling is, in my opinion, the least opinionated. | |||
// Other strategies are also viable, though: | |||
// Option 1) Return an empty string in case of error, but allow the user to | |||
// specify explicitly which errors to ignore. | |||
// Option 2) Return the partially evaluated string if it is itself a valid | |||
// string, otherwise return the empty string in case of error. | |||
// Option 3) Option 1 and 2. | |||
// Option 4) Always return an empty string for now and implement Option 1 as | |||
// needed, and document that the return string may not be empty in case of | |||
// error in the future. | |||
// I think Option 1 is best, but it is quite opinionated. | |||
// ToASCII is a wrapper for Punycode.ToASCII. | |||
func ToASCII(s string) (string, error) { | |||
return Punycode.process(s, true) | |||
} | |||
// ToUnicode is a wrapper for Punycode.ToUnicode. | |||
func ToUnicode(s string) (string, error) { | |||
return Punycode.process(s, false) | |||
} | |||
// An Option configures a Profile at creation time. | |||
type Option func(*options) | |||
// Transitional sets a Profile to use the Transitional mapping as defined in UTS | |||
// #46. This will cause, for example, "ß" to be mapped to "ss". Using the | |||
// transitional mapping provides a compromise between IDNA2003 and IDNA2008 | |||
// compatibility. It is used by most browsers when resolving domain names. This | |||
// option is only meaningful if combined with MapForLookup. | |||
func Transitional(transitional bool) Option { | |||
return func(o *options) { o.transitional = true } | |||
} | |||
// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts | |||
// are longer than allowed by the RFC. | |||
func VerifyDNSLength(verify bool) Option { | |||
return func(o *options) { o.verifyDNSLength = verify } | |||
} | |||
// RemoveLeadingDots removes leading label separators. Leading runes that map to | |||
// dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well. | |||
// | |||
// This is the behavior suggested by the UTS #46 and is adopted by some | |||
// browsers. | |||
func RemoveLeadingDots(remove bool) Option { | |||
return func(o *options) { o.removeLeadingDots = remove } | |||
} | |||
// ValidateLabels sets whether to check the mandatory label validation criteria | |||
// as defined in Section 5.4 of RFC 5891. This includes testing for correct use | |||
// of hyphens ('-'), normalization, validity of runes, and the context rules. | |||
func ValidateLabels(enable bool) Option { | |||
return func(o *options) { | |||
// Don't override existing mappings, but set one that at least checks | |||
// normalization if it is not set. | |||
if o.mapping == nil && enable { | |||
o.mapping = normalize | |||
} | |||
o.trie = trie | |||
o.validateLabels = enable | |||
o.fromPuny = validateFromPunycode | |||
} | |||
} | |||
// StrictDomainName limits the set of permissable ASCII characters to those | |||
// allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the | |||
// hyphen). This is set by default for MapForLookup and ValidateForRegistration. | |||
// | |||
// This option is useful, for instance, for browsers that allow characters | |||
// outside this range, for example a '_' (U+005F LOW LINE). See | |||
// http://www.rfc-editor.org/std/std3.txt for more details This option | |||
// corresponds to the UseSTD3ASCIIRules option in UTS #46. | |||
func StrictDomainName(use bool) Option { | |||
return func(o *options) { | |||
o.trie = trie | |||
o.useSTD3Rules = use | |||
o.fromPuny = validateFromPunycode | |||
} | |||
} | |||
// NOTE: the following options pull in tables. The tables should not be linked | |||
// in as long as the options are not used. | |||
// BidiRule enables the Bidi rule as defined in RFC 5893. Any application | |||
// that relies on proper validation of labels should include this rule. | |||
func BidiRule() Option { | |||
return func(o *options) { o.bidirule = bidirule.ValidString } | |||
} | |||
// ValidateForRegistration sets validation options to verify that a given IDN is | |||
// properly formatted for registration as defined by Section 4 of RFC 5891. | |||
func ValidateForRegistration() Option { | |||
return func(o *options) { | |||
o.mapping = validateRegistration | |||
StrictDomainName(true)(o) | |||
ValidateLabels(true)(o) | |||
VerifyDNSLength(true)(o) | |||
BidiRule()(o) | |||
} | |||
} | |||
// MapForLookup sets validation and mapping options such that a given IDN is | |||
// transformed for domain name lookup according to the requirements set out in | |||
// Section 5 of RFC 5891. The mappings follow the recommendations of RFC 5894, | |||
// RFC 5895 and UTS 46. It does not add the Bidi Rule. Use the BidiRule option | |||
// to add this check. | |||
// | |||
// The mappings include normalization and mapping case, width and other | |||
// compatibility mappings. | |||
func MapForLookup() Option { | |||
return func(o *options) { | |||
o.mapping = validateAndMap | |||
StrictDomainName(true)(o) | |||
ValidateLabels(true)(o) | |||
RemoveLeadingDots(true)(o) | |||
} | |||
} | |||
type options struct { | |||
transitional bool | |||
useSTD3Rules bool | |||
validateLabels bool | |||
verifyDNSLength bool | |||
removeLeadingDots bool | |||
trie *idnaTrie | |||
// fromPuny calls validation rules when converting A-labels to U-labels. | |||
fromPuny func(p *Profile, s string) error | |||
// mapping implements a validation and mapping step as defined in RFC 5895 | |||
// or UTS 46, tailored to, for example, domain registration or lookup. | |||
mapping func(p *Profile, s string) (string, error) | |||
// bidirule, if specified, checks whether s conforms to the Bidi Rule | |||
// defined in RFC 5893. | |||
bidirule func(s string) bool | |||
} | |||
// A Profile defines the configuration of a IDNA mapper. | |||
type Profile struct { | |||
options | |||
} | |||
func apply(o *options, opts []Option) { | |||
for _, f := range opts { | |||
f(o) | |||
} | |||
} | |||
// New creates a new Profile. | |||
// | |||
// With no options, the returned Profile is the most permissive and equals the | |||
// Punycode Profile. Options can be passed to further restrict the Profile. The | |||
// MapForLookup and ValidateForRegistration options set a collection of options, | |||
// for lookup and registration purposes respectively, which can be tailored by | |||
// adding more fine-grained options, where later options override earlier | |||
// options. | |||
func New(o ...Option) *Profile { | |||
p := &Profile{} | |||
apply(&p.options, o) | |||
return p | |||
} | |||
// ToASCII converts a domain or domain label to its ASCII form. For example, | |||
// ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and | |||
// ToASCII("golang") is "golang". If an error is encountered it will return | |||
// an error and a (partially) processed result. | |||
func (p *Profile) ToASCII(s string) (string, error) { | |||
return p.process(s, true) | |||
} | |||
// ToUnicode converts a domain or domain label to its Unicode form. For example, | |||
// ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and | |||
// ToUnicode("golang") is "golang". If an error is encountered it will return | |||
// an error and a (partially) processed result. | |||
func (p *Profile) ToUnicode(s string) (string, error) { | |||
pp := *p | |||
pp.transitional = false | |||
return pp.process(s, false) | |||
} | |||
// String reports a string with a description of the profile for debugging | |||
// purposes. The string format may change with different versions. | |||
func (p *Profile) String() string { | |||
s := "" | |||
if p.transitional { | |||
s = "Transitional" | |||
} else { | |||
s = "NonTransitional" | |||
} | |||
if p.useSTD3Rules { | |||
s += ":UseSTD3Rules" | |||
} | |||
if p.validateLabels { | |||
s += ":ValidateLabels" | |||
} | |||
if p.verifyDNSLength { | |||
s += ":VerifyDNSLength" | |||
} | |||
return s | |||
} | |||
var ( | |||
// Punycode is a Profile that does raw punycode processing with a minimum | |||
// of validation. | |||
Punycode *Profile = punycode | |||
// Lookup is the recommended profile for looking up domain names, according | |||
// to Section 5 of RFC 5891. The exact configuration of this profile may | |||
// change over time. | |||
Lookup *Profile = lookup | |||
// Display is the recommended profile for displaying domain names. | |||
// The configuration of this profile may change over time. | |||
Display *Profile = display | |||
// Registration is the recommended profile for checking whether a given | |||
// IDN is valid for registration, according to Section 4 of RFC 5891. | |||
Registration *Profile = registration | |||
punycode = &Profile{} | |||
lookup = &Profile{options{ | |||
transitional: true, | |||
useSTD3Rules: true, | |||
validateLabels: true, | |||
removeLeadingDots: true, | |||
trie: trie, | |||
fromPuny: validateFromPunycode, | |||
mapping: validateAndMap, | |||
bidirule: bidirule.ValidString, | |||
}} | |||
display = &Profile{options{ | |||
useSTD3Rules: true, | |||
validateLabels: true, | |||
removeLeadingDots: true, | |||
trie: trie, | |||
fromPuny: validateFromPunycode, | |||
mapping: validateAndMap, | |||
bidirule: bidirule.ValidString, | |||
}} | |||
registration = &Profile{options{ | |||
useSTD3Rules: true, | |||
validateLabels: true, | |||
verifyDNSLength: true, | |||
trie: trie, | |||
fromPuny: validateFromPunycode, | |||
mapping: validateRegistration, | |||
bidirule: bidirule.ValidString, | |||
}} | |||
// TODO: profiles | |||
// Register: recommended for approving domain names: don't do any mappings | |||
// but rather reject on invalid input. Bundle or block deviation characters. | |||
) | |||
type labelError struct{ label, code_ string } | |||
func (e labelError) code() string { return e.code_ } | |||
func (e labelError) Error() string { | |||
return fmt.Sprintf("idna: invalid label %q", e.label) | |||
} | |||
type runeError rune | |||
func (e runeError) code() string { return "P1" } | |||
func (e runeError) Error() string { | |||
return fmt.Sprintf("idna: disallowed rune %U", e) | |||
} | |||
// process implements the algorithm described in section 4 of UTS #46, | |||
// see https://www.unicode.org/reports/tr46. | |||
func (p *Profile) process(s string, toASCII bool) (string, error) { | |||
var err error | |||
if p.mapping != nil { | |||
s, err = p.mapping(p, s) | |||
} | |||
// Remove leading empty labels. | |||
if p.removeLeadingDots { | |||
for ; len(s) > 0 && s[0] == '.'; s = s[1:] { | |||
} | |||
} | |||
// It seems like we should only create this error on ToASCII, but the | |||
// UTS 46 conformance tests suggests we should always check this. | |||
if err == nil && p.verifyDNSLength && s == "" { | |||
err = &labelError{s, "A4"} | |||
} | |||
labels := labelIter{orig: s} | |||
for ; !labels.done(); labels.next() { | |||
label := labels.label() | |||
if label == "" { | |||
// Empty labels are not okay. The label iterator skips the last | |||
// label if it is empty. | |||
if err == nil && p.verifyDNSLength { | |||
err = &labelError{s, "A4"} | |||
} | |||
continue | |||
} | |||
if strings.HasPrefix(label, acePrefix) { | |||
u, err2 := decode(label[len(acePrefix):]) | |||
if err2 != nil { | |||
if err == nil { | |||
err = err2 | |||
} | |||
// Spec says keep the old label. | |||
continue | |||
} | |||
labels.set(u) | |||
if err == nil && p.validateLabels { | |||
err = p.fromPuny(p, u) | |||
} | |||
if err == nil { | |||
// This should be called on NonTransitional, according to the | |||
// spec, but that currently does not have any effect. Use the | |||
// original profile to preserve options. | |||
err = p.validateLabel(u) | |||
} | |||
} else if err == nil { | |||
err = p.validateLabel(label) | |||
} | |||
} | |||
if toASCII { | |||
for labels.reset(); !labels.done(); labels.next() { | |||
label := labels.label() | |||
if !ascii(label) { | |||
a, err2 := encode(acePrefix, label) | |||
if err == nil { | |||
err = err2 | |||
} | |||
label = a | |||
labels.set(a) | |||
} | |||
n := len(label) | |||
if p.verifyDNSLength && err == nil && (n == 0 || n > 63) { | |||
err = &labelError{label, "A4"} | |||
} | |||
} | |||
} | |||
s = labels.result() | |||
if toASCII && p.verifyDNSLength && err == nil { | |||
// Compute the length of the domain name minus the root label and its dot. | |||
n := len(s) | |||
if n > 0 && s[n-1] == '.' { | |||
n-- | |||
} | |||
if len(s) < 1 || n > 253 { | |||
err = &labelError{s, "A4"} | |||
} | |||
} | |||
return s, err | |||
} | |||
func normalize(p *Profile, s string) (string, error) { | |||
return norm.NFC.String(s), nil | |||
} | |||
func validateRegistration(p *Profile, s string) (string, error) { | |||
if !norm.NFC.IsNormalString(s) { | |||
return s, &labelError{s, "V1"} | |||
} | |||
for i := 0; i < len(s); { | |||
v, sz := trie.lookupString(s[i:]) | |||
// Copy bytes not copied so far. | |||
switch p.simplify(info(v).category()) { | |||
// TODO: handle the NV8 defined in the Unicode idna data set to allow | |||
// for strict conformance to IDNA2008. | |||
case valid, deviation: | |||
case disallowed, mapped, unknown, ignored: | |||
r, _ := utf8.DecodeRuneInString(s[i:]) | |||
return s, runeError(r) | |||
} | |||
i += sz | |||
} | |||
return s, nil | |||
} | |||
func validateAndMap(p *Profile, s string) (string, error) { | |||
var ( | |||
err error | |||
b []byte | |||
k int | |||
) | |||
for i := 0; i < len(s); { | |||
v, sz := trie.lookupString(s[i:]) | |||
start := i | |||
i += sz | |||
// Copy bytes not copied so far. | |||
switch p.simplify(info(v).category()) { | |||
case valid: | |||
continue | |||
case disallowed: | |||
if err == nil { | |||
r, _ := utf8.DecodeRuneInString(s[start:]) | |||
err = runeError(r) | |||
} | |||
continue | |||
case mapped, deviation: | |||
b = append(b, s[k:start]...) | |||
b = info(v).appendMapping(b, s[start:i]) | |||
case ignored: | |||
b = append(b, s[k:start]...) | |||
// drop the rune | |||
case unknown: | |||
b = append(b, s[k:start]...) | |||
b = append(b, "\ufffd"...) | |||
} | |||
k = i | |||
} | |||
if k == 0 { | |||
// No changes so far. | |||
s = norm.NFC.String(s) | |||
} else { | |||
b = append(b, s[k:]...) | |||
if norm.NFC.QuickSpan(b) != len(b) { | |||
b = norm.NFC.Bytes(b) | |||
} | |||
// TODO: the punycode converters require strings as input. | |||
s = string(b) | |||
} | |||
return s, err | |||
} | |||
// A labelIter allows iterating over domain name labels. | |||
type labelIter struct { | |||
orig string | |||
slice []string | |||
curStart int | |||
curEnd int | |||
i int | |||
} | |||
func (l *labelIter) reset() { | |||
l.curStart = 0 | |||
l.curEnd = 0 | |||
l.i = 0 | |||
} | |||
func (l *labelIter) done() bool { | |||
return l.curStart >= len(l.orig) | |||
} | |||
func (l *labelIter) result() string { | |||
if l.slice != nil { | |||
return strings.Join(l.slice, ".") | |||
} | |||
return l.orig | |||
} | |||
func (l *labelIter) label() string { | |||
if l.slice != nil { | |||
return l.slice[l.i] | |||
} | |||
p := strings.IndexByte(l.orig[l.curStart:], '.') | |||
l.curEnd = l.curStart + p | |||
if p == -1 { | |||
l.curEnd = len(l.orig) | |||
} | |||
return l.orig[l.curStart:l.curEnd] | |||
} | |||
// next sets the value to the next label. It skips the last label if it is empty. | |||
func (l *labelIter) next() { | |||
l.i++ | |||
if l.slice != nil { | |||
if l.i >= len(l.slice) || l.i == len(l.slice)-1 && l.slice[l.i] == "" { | |||
l.curStart = len(l.orig) | |||
} | |||
} else { | |||
l.curStart = l.curEnd + 1 | |||
if l.curStart == len(l.orig)-1 && l.orig[l.curStart] == '.' { | |||
l.curStart = len(l.orig) | |||
} | |||
} | |||
} | |||
func (l *labelIter) set(s string) { | |||
if l.slice == nil { | |||
l.slice = strings.Split(l.orig, ".") | |||
} | |||
l.slice[l.i] = s | |||
} | |||
// acePrefix is the ASCII Compatible Encoding prefix. | |||
const acePrefix = "xn--" | |||
func (p *Profile) simplify(cat category) category { | |||
switch cat { | |||
case disallowedSTD3Mapped: | |||
if p.useSTD3Rules { | |||
cat = disallowed | |||
} else { | |||
cat = mapped | |||
} | |||
case disallowedSTD3Valid: | |||
if p.useSTD3Rules { | |||
cat = disallowed | |||
} else { | |||
cat = valid | |||
} | |||
case deviation: | |||
if !p.transitional { | |||
cat = valid | |||
} | |||
case validNV8, validXV8: | |||
// TODO: handle V2008 | |||
cat = valid | |||
} | |||
return cat | |||
} | |||
func validateFromPunycode(p *Profile, s string) error { | |||
if !norm.NFC.IsNormalString(s) { | |||
return &labelError{s, "V1"} | |||
} | |||
for i := 0; i < len(s); { | |||
v, sz := trie.lookupString(s[i:]) | |||
if c := p.simplify(info(v).category()); c != valid && c != deviation { | |||
return &labelError{s, "V6"} | |||
} | |||
i += sz | |||
} | |||
return nil | |||
} | |||
const ( | |||
zwnj = "\u200c" | |||
zwj = "\u200d" | |||
) | |||
type joinState int8 | |||
const ( | |||
stateStart joinState = iota | |||
stateVirama | |||
stateBefore | |||
stateBeforeVirama | |||
stateAfter | |||
stateFAIL | |||
) | |||
var joinStates = [][numJoinTypes]joinState{ | |||
stateStart: { | |||
joiningL: stateBefore, | |||
joiningD: stateBefore, | |||
joinZWNJ: stateFAIL, | |||
joinZWJ: stateFAIL, | |||
joinVirama: stateVirama, | |||
}, | |||
stateVirama: { | |||
joiningL: stateBefore, | |||
joiningD: stateBefore, | |||
}, | |||
stateBefore: { | |||
joiningL: stateBefore, | |||
joiningD: stateBefore, | |||
joiningT: stateBefore, | |||
joinZWNJ: stateAfter, | |||
joinZWJ: stateFAIL, | |||
joinVirama: stateBeforeVirama, | |||
}, | |||
stateBeforeVirama: { | |||
joiningL: stateBefore, | |||
joiningD: stateBefore, | |||
joiningT: stateBefore, | |||
}, | |||
stateAfter: { | |||
joiningL: stateFAIL, | |||
joiningD: stateBefore, | |||
joiningT: stateAfter, | |||
joiningR: stateStart, | |||
joinZWNJ: stateFAIL, | |||
joinZWJ: stateFAIL, | |||
joinVirama: stateAfter, // no-op as we can't accept joiners here | |||
}, | |||
stateFAIL: { | |||
0: stateFAIL, | |||
joiningL: stateFAIL, | |||
joiningD: stateFAIL, | |||
joiningT: stateFAIL, | |||
joiningR: stateFAIL, | |||
joinZWNJ: stateFAIL, | |||
joinZWJ: stateFAIL, | |||
joinVirama: stateFAIL, | |||
}, | |||
} | |||
// validateLabel validates the criteria from Section 4.1. Item 1, 4, and 6 are | |||
// already implicitly satisfied by the overall implementation. | |||
func (p *Profile) validateLabel(s string) error { | |||
if s == "" { | |||
if p.verifyDNSLength { | |||
return &labelError{s, "A4"} | |||
} | |||
return nil | |||
} | |||
if p.bidirule != nil && !p.bidirule(s) { | |||
return &labelError{s, "B"} | |||
} | |||
if !p.validateLabels { | |||
return nil | |||
} | |||
trie := p.trie // p.validateLabels is only set if trie is set. | |||
if len(s) > 4 && s[2] == '-' && s[3] == '-' { | |||
return &labelError{s, "V2"} | |||
} | |||
if s[0] == '-' || s[len(s)-1] == '-' { | |||
return &labelError{s, "V3"} | |||
} | |||
// TODO: merge the use of this in the trie. | |||
v, sz := trie.lookupString(s) | |||
x := info(v) | |||
if x.isModifier() { | |||
return &labelError{s, "V5"} | |||
} | |||
// Quickly return in the absence of zero-width (non) joiners. | |||
if strings.Index(s, zwj) == -1 && strings.Index(s, zwnj) == -1 { | |||
return nil | |||
} | |||
st := stateStart | |||
for i := 0; ; { | |||
jt := x.joinType() | |||
if s[i:i+sz] == zwj { | |||
jt = joinZWJ | |||
} else if s[i:i+sz] == zwnj { | |||
jt = joinZWNJ | |||
} | |||
st = joinStates[st][jt] | |||
if x.isViramaModifier() { | |||
st = joinStates[st][joinVirama] | |||
} | |||
if i += sz; i == len(s) { | |||
break | |||
} | |||
v, sz = trie.lookupString(s[i:]) | |||
x = info(v) | |||
} | |||
if st == stateFAIL || st == stateAfter { | |||
return &labelError{s, "C"} | |||
} | |||
return nil | |||
} | |||
func ascii(s string) bool { | |||
for i := 0; i < len(s); i++ { | |||
if s[i] >= utf8.RuneSelf { | |||
return false | |||
} | |||
} | |||
return true | |||
} |
@ -0,0 +1,203 @@ | |||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
// Copyright 2016 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. | |||
package idna | |||
// This file implements the Punycode algorithm from RFC 3492. | |||
import ( | |||
"math" | |||
"strings" | |||
"unicode/utf8" | |||
) | |||
// These parameter values are specified in section 5. | |||
// | |||
// All computation is done with int32s, so that overflow behavior is identical | |||
// regardless of whether int is 32-bit or 64-bit. | |||
const ( | |||
base int32 = 36 | |||
damp int32 = 700 | |||
initialBias int32 = 72 | |||
initialN int32 = 128 | |||
skew int32 = 38 | |||
tmax int32 = 26 | |||
tmin int32 = 1 | |||
) | |||
func punyError(s string) error { return &labelError{s, "A3"} } | |||
// decode decodes a string as specified in section 6.2. | |||
func decode(encoded string) (string, error) { | |||
if encoded == "" { | |||
return "", nil | |||
} | |||
pos := 1 + strings.LastIndex(encoded, "-") | |||
if pos == 1 { | |||
return "", punyError(encoded) | |||
} | |||
if pos == len(encoded) { | |||
return encoded[:len(encoded)-1], nil | |||
} | |||
output := make([]rune, 0, len(encoded)) | |||
if pos != 0 { | |||
for _, r := range encoded[:pos-1] { | |||
output = append(output, r) | |||
} | |||
} | |||
i, n, bias := int32(0), initialN, initialBias | |||
for pos < len(encoded) { | |||
oldI, w := i, int32(1) | |||
for k := base; ; k += base { | |||
if pos == len(encoded) { | |||
return "", punyError(encoded) | |||
} | |||
digit, ok := decodeDigit(encoded[pos]) | |||
if !ok { | |||
return "", punyError(encoded) | |||
} | |||
pos++ | |||
i += digit * w | |||
if i < 0 { | |||
return "", punyError(encoded) | |||
} | |||
t := k - bias | |||
if t < tmin { | |||
t = tmin | |||
} else if t > tmax { | |||
t = tmax | |||
} | |||
if digit < t { | |||
break | |||
} | |||
w *= base - t | |||
if w >= math.MaxInt32/base { | |||
return "", punyError(encoded) | |||
} | |||
} | |||
x := int32(len(output) + 1) | |||
bias = adapt(i-oldI, x, oldI == 0) | |||
n += i / x | |||
i %= x | |||
if n > utf8.MaxRune || len(output) >= 1024 { | |||
return "", punyError(encoded) | |||
} | |||
output = append(output, 0) | |||
copy(output[i+1:], output[i:]) | |||
output[i] = n | |||
i++ | |||
} | |||
return string(output), nil | |||
} | |||
// encode encodes a string as specified in section 6.3 and prepends prefix to | |||
// the result. | |||
// | |||
// The "while h < length(input)" line in the specification becomes "for | |||
// remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes. | |||
func encode(prefix, s string) (string, error) { | |||
output := make([]byte, len(prefix), len(prefix)+1+2*len(s)) | |||
copy(output, prefix) | |||
delta, n, bias := int32(0), initialN, initialBias | |||
b, remaining := int32(0), int32(0) | |||
for _, r := range s { | |||
if r < 0x80 { | |||
b++ | |||
output = append(output, byte(r)) | |||
} else { | |||
remaining++ | |||
} | |||
} | |||
h := b | |||
if b > 0 { | |||
output = append(output, '-') | |||
} | |||
for remaining != 0 { | |||
m := int32(0x7fffffff) | |||
for _, r := range s { | |||
if m > r && r >= n { | |||
m = r | |||
} | |||
} | |||
delta += (m - n) * (h + 1) | |||
if delta < 0 { | |||
return "", punyError(s) | |||
} | |||
n = m | |||
for _, r := range s { | |||
if r < n { | |||
delta++ | |||
if delta < 0 { | |||
return "", punyError(s) | |||
} | |||
continue | |||
} | |||
if r > n { | |||
continue | |||
} | |||
q := delta | |||
for k := base; ; k += base { | |||
t := k - bias | |||
if t < tmin { | |||
t = tmin | |||
} else if t > tmax { | |||
t = tmax | |||
} | |||
if q < t { | |||
break | |||
} | |||
output = append(output, encodeDigit(t+(q-t)%(base-t))) | |||
q = (q - t) / (base - t) | |||
} | |||
output = append(output, encodeDigit(q)) | |||
bias = adapt(delta, h+1, h == b) | |||
delta = 0 | |||
h++ | |||
remaining-- | |||
} | |||
delta++ | |||
n++ | |||
} | |||
return string(output), nil | |||
} | |||
func decodeDigit(x byte) (digit int32, ok bool) { | |||
switch { | |||
case '0' <= x && x <= '9': | |||
return int32(x - ('0' - 26)), true | |||
case 'A' <= x && x <= 'Z': | |||
return int32(x - 'A'), true | |||
case 'a' <= x && x <= 'z': | |||
return int32(x - 'a'), true | |||
} | |||
return 0, false | |||
} | |||
func encodeDigit(digit int32) byte { | |||
switch { | |||
case 0 <= digit && digit < 26: | |||
return byte(digit + 'a') | |||
case 26 <= digit && digit < 36: | |||
return byte(digit + ('0' - 26)) | |||
} | |||
panic("idna: internal error in punycode encoding") | |||
} | |||
// adapt is the bias adaptation function specified in section 6.1. | |||
func adapt(delta, numPoints int32, firstTime bool) int32 { | |||
if firstTime { | |||
delta /= damp | |||
} else { | |||
delta /= 2 | |||
} | |||
delta += delta / numPoints | |||
k := int32(0) | |||
for delta > ((base-tmin)*tmax)/2 { | |||
delta /= base - tmin | |||
k += base | |||
} | |||
return k + (base-tmin+1)*delta/(delta+skew) | |||
} |
@ -0,0 +1,72 @@ | |||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
// Copyright 2016 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. | |||
package idna | |||
// appendMapping appends the mapping for the respective rune. isMapped must be | |||
// true. A mapping is a categorization of a rune as defined in UTS #46. | |||
func (c info) appendMapping(b []byte, s string) []byte { | |||
index := int(c >> indexShift) | |||
if c&xorBit == 0 { | |||
s := mappings[index:] | |||
return append(b, s[1:s[0]+1]...) | |||
} | |||
b = append(b, s...) | |||
if c&inlineXOR == inlineXOR { | |||
// TODO: support and handle two-byte inline masks | |||
b[len(b)-1] ^= byte(index) | |||
} else { | |||
for p := len(b) - int(xorData[index]); p < len(b); p++ { | |||
index++ | |||
b[p] ^= xorData[index] | |||
} | |||
} | |||
return b | |||
} | |||
// Sparse block handling code. | |||
type valueRange struct { | |||
value uint16 // header: value:stride | |||
lo, hi byte // header: lo:n | |||
} | |||
type sparseBlocks struct { | |||
values []valueRange | |||
offset []uint16 | |||
} | |||
var idnaSparse = sparseBlocks{ | |||
values: idnaSparseValues[:], | |||
offset: idnaSparseOffset[:], | |||
} | |||
// Don't use newIdnaTrie to avoid unconditional linking in of the table. | |||
var trie = &idnaTrie{} | |||
// lookup determines the type of block n and looks up the value for b. | |||
// For n < t.cutoff, the block is a simple lookup table. Otherwise, the block | |||
// is a list of ranges with an accompanying value. Given a matching range r, | |||
// the value for b is by r.value + (b - r.lo) * stride. | |||
func (t *sparseBlocks) lookup(n uint32, b byte) uint16 { | |||
offset := t.offset[n] | |||
header := t.values[offset] | |||
lo := offset + 1 | |||
hi := lo + uint16(header.lo) | |||
for lo < hi { | |||
m := lo + (hi-lo)/2 | |||
r := t.values[m] | |||
if r.lo <= b && b <= r.hi { | |||
return r.value + uint16(b-r.lo)*header.value | |||
} | |||
if b < r.lo { | |||
hi = m | |||
} else { | |||
lo = m + 1 | |||
} | |||
} | |||
return 0 | |||
} |
@ -0,0 +1,119 @@ | |||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
package idna | |||
// This file contains definitions for interpreting the trie value of the idna | |||
// trie generated by "go run gen*.go". It is shared by both the generator | |||
// program and the resultant package. Sharing is achieved by the generator | |||
// copying gen_trieval.go to trieval.go and changing what's above this comment. | |||
// info holds information from the IDNA mapping table for a single rune. It is | |||
// the value returned by a trie lookup. In most cases, all information fits in | |||
// a 16-bit value. For mappings, this value may contain an index into a slice | |||
// with the mapped string. Such mappings can consist of the actual mapped value | |||
// or an XOR pattern to be applied to the bytes of the UTF8 encoding of the | |||
// input rune. This technique is used by the cases packages and reduces the | |||
// table size significantly. | |||
// | |||
// The per-rune values have the following format: | |||
// | |||
// if mapped { | |||
// if inlinedXOR { | |||
// 15..13 inline XOR marker | |||
// 12..11 unused | |||
// 10..3 inline XOR mask | |||
// } else { | |||
// 15..3 index into xor or mapping table | |||
// } | |||
// } else { | |||
// 15..14 unused | |||
// 13 mayNeedNorm | |||
// 12..11 attributes | |||
// 10..8 joining type | |||
// 7..3 category type | |||
// } | |||
// 2 use xor pattern | |||
// 1..0 mapped category | |||
// | |||
// See the definitions below for a more detailed description of the various | |||
// bits. | |||
type info uint16 | |||
const ( | |||
catSmallMask = 0x3 | |||
catBigMask = 0xF8 | |||
indexShift = 3 | |||
xorBit = 0x4 // interpret the index as an xor pattern | |||
inlineXOR = 0xE000 // These bits are set if the XOR pattern is inlined. | |||
joinShift = 8 | |||
joinMask = 0x07 | |||
// Attributes | |||
attributesMask = 0x1800 | |||
viramaModifier = 0x1800 | |||
modifier = 0x1000 | |||
rtl = 0x0800 | |||
mayNeedNorm = 0x2000 | |||
) | |||
// A category corresponds to a category defined in the IDNA mapping table. | |||
type category uint16 | |||
const ( | |||
unknown category = 0 // not currently defined in unicode. | |||
mapped category = 1 | |||
disallowedSTD3Mapped category = 2 | |||
deviation category = 3 | |||
) | |||
const ( | |||
valid category = 0x08 | |||
validNV8 category = 0x18 | |||
validXV8 category = 0x28 | |||
disallowed category = 0x40 | |||
disallowedSTD3Valid category = 0x80 | |||
ignored category = 0xC0 | |||
) | |||
// join types and additional rune information | |||
const ( | |||
joiningL = (iota + 1) | |||
joiningD | |||
joiningT | |||
joiningR | |||
//the following types are derived during processing | |||
joinZWJ | |||
joinZWNJ | |||
joinVirama | |||
numJoinTypes | |||
) | |||
func (c info) isMapped() bool { | |||
return c&0x3 != 0 | |||
} | |||
func (c info) category() category { | |||
small := c & catSmallMask | |||
if small != 0 { | |||
return category(small) | |||
} | |||
return category(c & catBigMask) | |||
} | |||
func (c info) joinType() info { | |||
if c.isMapped() { | |||
return 0 | |||
} | |||
return (c >> joinShift) & joinMask | |||
} | |||
func (c info) isModifier() bool { | |||
return c&(modifier|catSmallMask) == modifier | |||
} | |||
func (c info) isViramaModifier() bool { | |||
return c&(attributesMask|catSmallMask) == viramaModifier | |||
} |
@ -0,0 +1,168 @@ | |||
// Copyright 2018 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. | |||
package socks | |||
import ( | |||
"context" | |||
"errors" | |||
"io" | |||
"net" | |||
"strconv" | |||
"time" | |||
) | |||
var ( | |||
noDeadline = time.Time{} | |||
aLongTimeAgo = time.Unix(1, 0) | |||
) | |||
func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) { | |||
host, port, err := splitHostPort(address) | |||
if err != nil { | |||
return nil, err | |||
} | |||
if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { | |||
c.SetDeadline(deadline) | |||
defer c.SetDeadline(noDeadline) | |||
} | |||
if ctx != context.Background() { | |||
errCh := make(chan error, 1) | |||
done := make(chan struct{}) | |||
defer func() { | |||
close(done) | |||
if ctxErr == nil { | |||
ctxErr = <-errCh | |||
} | |||
}() | |||
go func() { | |||
select { | |||
case <-ctx.Done(): | |||
c.SetDeadline(aLongTimeAgo) | |||
errCh <- ctx.Err() | |||
case <-done: | |||
errCh <- nil | |||
} | |||
}() | |||
} | |||
b := make([]byte, 0, 6+len(host)) // the size here is just an estimate | |||
b = append(b, Version5) | |||
if len(d.AuthMethods) == 0 || d.Authenticate == nil { | |||
b = append(b, 1, byte(AuthMethodNotRequired)) | |||
} else { | |||
ams := d.AuthMethods | |||
if len(ams) > 255 { | |||
return nil, errors.New("too many authentication methods") | |||
} | |||
b = append(b, byte(len(ams))) | |||
for _, am := range ams { | |||
b = append(b, byte(am)) | |||
} | |||
} | |||
if _, ctxErr = c.Write(b); ctxErr != nil { | |||
return | |||
} | |||
if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil { | |||
return | |||
} | |||
if b[0] != Version5 { | |||
return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) | |||
} | |||
am := AuthMethod(b[1]) | |||
if am == AuthMethodNoAcceptableMethods { | |||
return nil, errors.New("no acceptable authentication methods") | |||
} | |||
if d.Authenticate != nil { | |||
if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil { | |||
return | |||
} | |||
} | |||
b = b[:0] | |||
b = append(b, Version5, byte(d.cmd), 0) | |||
if ip := net.ParseIP(host); ip != nil { | |||
if ip4 := ip.To4(); ip4 != nil { | |||
b = append(b, AddrTypeIPv4) | |||
b = append(b, ip4...) | |||
} else if ip6 := ip.To16(); ip6 != nil { | |||
b = append(b, AddrTypeIPv6) | |||
b = append(b, ip6...) | |||
} else { | |||
return nil, errors.New("unknown address type") | |||
} | |||
} else { | |||
if len(host) > 255 { | |||
return nil, errors.New("FQDN too long") | |||
} | |||
b = append(b, AddrTypeFQDN) | |||
b = append(b, byte(len(host))) | |||
b = append(b, host...) | |||
} | |||
b = append(b, byte(port>>8), byte(port)) | |||
if _, ctxErr = c.Write(b); ctxErr != nil { | |||
return | |||
} | |||
if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil { | |||
return | |||
} | |||
if b[0] != Version5 { | |||
return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) | |||
} | |||
if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded { | |||
return nil, errors.New("unknown error " + cmdErr.String()) | |||
} | |||
if b[2] != 0 { | |||
return nil, errors.New("non-zero reserved field") | |||
} | |||
l := 2 | |||
var a Addr | |||
switch b[3] { | |||
case AddrTypeIPv4: | |||
l += net.IPv4len | |||
a.IP = make(net.IP, net.IPv4len) | |||
case AddrTypeIPv6: | |||
l += net.IPv6len | |||
a.IP = make(net.IP, net.IPv6len) | |||
case AddrTypeFQDN: | |||
if _, err := io.ReadFull(c, b[:1]); err != nil { | |||
return nil, err | |||
} | |||
l += int(b[0]) | |||
default: | |||
return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3]))) | |||
} | |||
if cap(b) < l { | |||
b = make([]byte, l) | |||
} else { | |||
b = b[:l] | |||
} | |||
if _, ctxErr = io.ReadFull(c, b); ctxErr != nil { | |||
return | |||
} | |||
if a.IP != nil { | |||
copy(a.IP, b) | |||
} else { | |||
a.Name = string(b[:len(b)-2]) | |||
} | |||
a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1]) | |||
return &a, nil | |||
} | |||
func splitHostPort(address string) (string, int, error) { | |||
host, port, err := net.SplitHostPort(address) | |||
if err != nil { | |||
return "", 0, err | |||
} | |||
portnum, err := strconv.Atoi(port) | |||
if err != nil { | |||
return "", 0, err | |||
} | |||
if 1 > portnum || portnum > 0xffff { | |||
return "", 0, errors.New("port number out of range " + port) | |||
} | |||
return host, portnum, nil | |||
} |
@ -0,0 +1,317 @@ | |||
// Copyright 2018 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. | |||
// Package socks provides a SOCKS version 5 client implementation. | |||
// | |||
// SOCKS protocol version 5 is defined in RFC 1928. | |||
// Username/Password authentication for SOCKS version 5 is defined in | |||
// RFC 1929. | |||
package socks | |||
import ( | |||
"context" | |||
"errors" | |||
"io" | |||
"net" | |||
"strconv" | |||
) | |||
// A Command represents a SOCKS command. | |||
type Command int | |||
func (cmd Command) String() string { | |||
switch cmd { | |||
case CmdConnect: | |||
return "socks connect" | |||
case cmdBind: | |||
return "socks bind" | |||
default: | |||
return "socks " + strconv.Itoa(int(cmd)) | |||
} | |||
} | |||
// An AuthMethod represents a SOCKS authentication method. | |||
type AuthMethod int | |||
// A Reply represents a SOCKS command reply code. | |||
type Reply int | |||
func (code Reply) String() string { | |||
switch code { | |||
case StatusSucceeded: | |||
return "succeeded" | |||
case 0x01: | |||
return "general SOCKS server failure" | |||
case 0x02: | |||
return "connection not allowed by ruleset" | |||
case 0x03: | |||
return "network unreachable" | |||
case 0x04: | |||
return "host unreachable" | |||
case 0x05: | |||
return "connection refused" | |||
case 0x06: | |||
return "TTL expired" | |||
case 0x07: | |||
return "command not supported" | |||
case 0x08: | |||
return "address type not supported" | |||
default: | |||
return "unknown code: " + strconv.Itoa(int(code)) | |||
} | |||
} | |||
// Wire protocol constants. | |||
const ( | |||
Version5 = 0x05 | |||
AddrTypeIPv4 = 0x01 | |||
AddrTypeFQDN = 0x03 | |||
AddrTypeIPv6 = 0x04 | |||
CmdConnect Command = 0x01 // establishes an active-open forward proxy connection | |||
cmdBind Command = 0x02 // establishes a passive-open forward proxy connection | |||
AuthMethodNotRequired AuthMethod = 0x00 // no authentication required | |||
AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password | |||
AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods | |||
StatusSucceeded Reply = 0x00 | |||
) | |||
// An Addr represents a SOCKS-specific address. | |||
// Either Name or IP is used exclusively. | |||
type Addr struct { | |||
Name string // fully-qualified domain name | |||
IP net.IP | |||
Port int | |||
} | |||
func (a *Addr) Network() string { return "socks" } | |||
func (a *Addr) String() string { | |||
if a == nil { | |||
return "<nil>" | |||
} | |||
port := strconv.Itoa(a.Port) | |||
if a.IP == nil { | |||
return net.JoinHostPort(a.Name, port) | |||
} | |||
return net.JoinHostPort(a.IP.String(), port) | |||
} | |||
// A Conn represents a forward proxy connection. | |||
type Conn struct { | |||
net.Conn | |||
boundAddr net.Addr | |||
} | |||
// BoundAddr returns the address assigned by the proxy server for | |||
// connecting to the command target address from the proxy server. | |||
func (c *Conn) BoundAddr() net.Addr { | |||
if c == nil { | |||
return nil | |||
} | |||
return c.boundAddr | |||
} | |||
// A Dialer holds SOCKS-specific options. | |||
type Dialer struct { | |||
cmd Command // either CmdConnect or cmdBind | |||
proxyNetwork string // network between a proxy server and a client | |||
proxyAddress string // proxy server address | |||
// ProxyDial specifies the optional dial function for | |||
// establishing the transport connection. | |||
ProxyDial func(context.Context, string, string) (net.Conn, error) | |||
// AuthMethods specifies the list of request authention | |||
// methods. | |||
// If empty, SOCKS client requests only AuthMethodNotRequired. | |||
AuthMethods []AuthMethod | |||
// Authenticate specifies the optional authentication | |||
// function. It must be non-nil when AuthMethods is not empty. | |||
// It must return an error when the authentication is failed. | |||
Authenticate func(context.Context, io.ReadWriter, AuthMethod) error | |||
} | |||
// DialContext connects to the provided address on the provided | |||
// network. | |||
// | |||
// The returned error value may be a net.OpError. When the Op field of | |||
// net.OpError contains "socks", the Source field contains a proxy | |||
// server address and the Addr field contains a command target | |||
// address. | |||
// | |||
// See func Dial of the net package of standard library for a | |||
// description of the network and address parameters. | |||
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { | |||
if err := d.validateTarget(network, address); err != nil { | |||
proxy, dst, _ := d.pathAddrs(address) | |||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | |||
} | |||
if ctx == nil { | |||
proxy, dst, _ := d.pathAddrs(address) | |||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} | |||
} | |||
var err error | |||
var c net.Conn | |||
if d.ProxyDial != nil { | |||
c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress) | |||
} else { | |||
var dd net.Dialer | |||
c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress) | |||
} | |||
if err != nil { | |||
proxy, dst, _ := d.pathAddrs(address) | |||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | |||
} | |||
a, err := d.connect(ctx, c, address) | |||
if err != nil { | |||
c.Close() | |||
proxy, dst, _ := d.pathAddrs(address) | |||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | |||
} | |||
return &Conn{Conn: c, boundAddr: a}, nil | |||
} | |||
// DialWithConn initiates a connection from SOCKS server to the target | |||
// network and address using the connection c that is already | |||
// connected to the SOCKS server. | |||
// | |||
// It returns the connection's local address assigned by the SOCKS | |||
// server. | |||
func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) { | |||
if err := d.validateTarget(network, address); err != nil { | |||
proxy, dst, _ := d.pathAddrs(address) | |||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | |||
} | |||
if ctx == nil { | |||
proxy, dst, _ := d.pathAddrs(address) | |||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} | |||
} | |||
a, err := d.connect(ctx, c, address) | |||
if err != nil { | |||
proxy, dst, _ := d.pathAddrs(address) | |||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | |||
} | |||
return a, nil | |||
} | |||
// Dial connects to the provided address on the provided network. | |||
// | |||
// Unlike DialContext, it returns a raw transport connection instead | |||
// of a forward proxy connection. | |||
// | |||
// Deprecated: Use DialContext or DialWithConn instead. | |||
func (d *Dialer) Dial(network, address string) (net.Conn, error) { | |||
if err := d.validateTarget(network, address); err != nil { | |||
proxy, dst, _ := d.pathAddrs(address) | |||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | |||
} | |||
var err error | |||
var c net.Conn | |||
if d.ProxyDial != nil { | |||
c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress) | |||
} else { | |||
c, err = net.Dial(d.proxyNetwork, d.proxyAddress) | |||
} | |||
if err != nil { | |||
proxy, dst, _ := d.pathAddrs(address) | |||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | |||
} | |||
if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil { | |||
c.Close() | |||
return nil, err | |||
} | |||
return c, nil | |||
} | |||
func (d *Dialer) validateTarget(network, address string) error { | |||
switch network { | |||
case "tcp", "tcp6", "tcp4": | |||
default: | |||
return errors.New("network not implemented") | |||
} | |||
switch d.cmd { | |||
case CmdConnect, cmdBind: | |||
default: | |||
return errors.New("command not implemented") | |||
} | |||
return nil | |||
} | |||
func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) { | |||
for i, s := range []string{d.proxyAddress, address} { | |||
host, port, err := splitHostPort(s) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
a := &Addr{Port: port} | |||
a.IP = net.ParseIP(host) | |||
if a.IP == nil { | |||
a.Name = host | |||
} | |||
if i == 0 { | |||
proxy = a | |||
} else { | |||
dst = a | |||
} | |||
} | |||
return | |||
} | |||
// NewDialer returns a new Dialer that dials through the provided | |||
// proxy server's network and address. | |||
func NewDialer(network, address string) *Dialer { | |||
return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect} | |||
} | |||
const ( | |||
authUsernamePasswordVersion = 0x01 | |||
authStatusSucceeded = 0x00 | |||
) | |||
// UsernamePassword are the credentials for the username/password | |||
// authentication method. | |||
type UsernamePassword struct { | |||
Username string | |||
Password string | |||
} | |||
// Authenticate authenticates a pair of username and password with the | |||
// proxy server. | |||
func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error { | |||
switch auth { | |||
case AuthMethodNotRequired: | |||
return nil | |||
case AuthMethodUsernamePassword: | |||
if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 { | |||
return errors.New("invalid username/password") | |||
} | |||
b := []byte{authUsernamePasswordVersion} | |||
b = append(b, byte(len(up.Username))) | |||
b = append(b, up.Username...) | |||
b = append(b, byte(len(up.Password))) | |||
b = append(b, up.Password...) | |||
// TODO(mikio): handle IO deadlines and cancelation if | |||
// necessary | |||
if _, err := rw.Write(b); err != nil { | |||
return err | |||
} | |||
if _, err := io.ReadFull(rw, b[:2]); err != nil { | |||
return err | |||
} | |||
if b[0] != authUsernamePasswordVersion { | |||
return errors.New("invalid username/password version") | |||
} | |||
if b[1] != authStatusSucceeded { | |||
return errors.New("username/password authentication failed") | |||
} | |||
return nil | |||
} | |||
return errors.New("unsupported authentication method " + strconv.Itoa(int(auth))) | |||
} |
@ -0,0 +1,54 @@ | |||
// Copyright 2019 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. | |||
package proxy | |||
import ( | |||
"context" | |||
"net" | |||
) | |||
// A ContextDialer dials using a context. | |||
type ContextDialer interface { | |||
DialContext(ctx context.Context, network, address string) (net.Conn, error) | |||
} | |||
// Dial works like DialContext on net.Dialer but using a dialer returned by FromEnvironment. | |||
// | |||
// The passed ctx is only used for returning the Conn, not the lifetime of the Conn. | |||
// | |||
// Custom dialers (registered via RegisterDialerType) that do not implement ContextDialer | |||
// can leak a goroutine for as long as it takes the underlying Dialer implementation to timeout. | |||
// | |||
// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed. | |||
func Dial(ctx context.Context, network, address string) (net.Conn, error) { | |||
d := FromEnvironment() | |||
if xd, ok := d.(ContextDialer); ok { | |||
return xd.DialContext(ctx, network, address) | |||
} | |||
return dialContext(ctx, d, network, address) | |||
} | |||
// WARNING: this can leak a goroutine for as long as the underlying Dialer implementation takes to timeout | |||
// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed. | |||
func dialContext(ctx context.Context, d Dialer, network, address string) (net.Conn, error) { | |||
var ( | |||
conn net.Conn | |||
done = make(chan struct{}, 1) | |||
err error | |||
) | |||
go func() { | |||
conn, err = d.Dial(network, address) | |||
close(done) | |||
if conn != nil && ctx.Err() != nil { | |||
conn.Close() | |||
} | |||
}() | |||
select { | |||
case <-ctx.Done(): | |||
err = ctx.Err() | |||
case <-done: | |||
} | |||
return conn, err | |||
} |
@ -0,0 +1,31 @@ | |||
// Copyright 2011 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. | |||
package proxy | |||
import ( | |||
"context" | |||
"net" | |||
) | |||
type direct struct{} | |||
// Direct implements Dialer by making network connections directly using net.Dial or net.DialContext. | |||
var Direct = direct{} | |||
var ( | |||
_ Dialer = Direct | |||
_ ContextDialer = Direct | |||
) | |||
// Dial directly invokes net.Dial with the supplied parameters. | |||
func (direct) Dial(network, addr string) (net.Conn, error) { | |||
return net.Dial(network, addr) | |||
} | |||
// DialContext instantiates a net.Dialer and invokes its DialContext receiver with the supplied parameters. | |||
func (direct) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { | |||
var d net.Dialer | |||
return d.DialContext(ctx, network, addr) | |||
} |
@ -0,0 +1,155 @@ | |||
// Copyright 2011 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. | |||
package proxy | |||
import ( | |||
"context" | |||
"net" | |||
"strings" | |||
) | |||
// A PerHost directs connections to a default Dialer unless the host name | |||
// requested matches one of a number of exceptions. | |||
type PerHost struct { | |||
def, bypass Dialer | |||
bypassNetworks []*net.IPNet | |||
bypassIPs []net.IP | |||
bypassZones []string | |||
bypassHosts []string | |||
} | |||
// NewPerHost returns a PerHost Dialer that directs connections to either | |||
// defaultDialer or bypass, depending on whether the connection matches one of | |||
// the configured rules. | |||
func NewPerHost(defaultDialer, bypass Dialer) *PerHost { | |||
return &PerHost{ | |||
def: defaultDialer, | |||
bypass: bypass, | |||
} | |||
} | |||
// Dial connects to the address addr on the given network through either | |||
// defaultDialer or bypass. | |||
func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) { | |||
host, _, err := net.SplitHostPort(addr) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return p.dialerForRequest(host).Dial(network, addr) | |||
} | |||
// DialContext connects to the address addr on the given network through either | |||
// defaultDialer or bypass. | |||
func (p *PerHost) DialContext(ctx context.Context, network, addr string) (c net.Conn, err error) { | |||
host, _, err := net.SplitHostPort(addr) | |||
if err != nil { | |||
return nil, err | |||
} | |||
d := p.dialerForRequest(host) | |||
if x, ok := d.(ContextDialer); ok { | |||
return x.DialContext(ctx, network, addr) | |||
} | |||
return dialContext(ctx, d, network, addr) | |||
} | |||
func (p *PerHost) dialerForRequest(host string) Dialer { | |||
if ip := net.ParseIP(host); ip != nil { | |||
for _, net := range p.bypassNetworks { | |||
if net.Contains(ip) { | |||
return p.bypass | |||
} | |||
} | |||
for _, bypassIP := range p.bypassIPs { | |||
if bypassIP.Equal(ip) { | |||
return p.bypass | |||
} | |||
} | |||
return p.def | |||
} | |||
for _, zone := range p.bypassZones { | |||
if strings.HasSuffix(host, zone) { | |||
return p.bypass | |||
} | |||
if host == zone[1:] { | |||
// For a zone ".example.com", we match "example.com" | |||
// too. | |||
return p.bypass | |||
} | |||
} | |||
for _, bypassHost := range p.bypassHosts { | |||
if bypassHost == host { | |||
return p.bypass | |||
} | |||
} | |||
return p.def | |||
} | |||
// AddFromString parses a string that contains comma-separated values | |||
// specifying hosts that should use the bypass proxy. Each value is either an | |||
// IP address, a CIDR range, a zone (*.example.com) or a host name | |||
// (localhost). A best effort is made to parse the string and errors are | |||
// ignored. | |||
func (p *PerHost) AddFromString(s string) { | |||
hosts := strings.Split(s, ",") | |||
for _, host := range hosts { | |||
host = strings.TrimSpace(host) | |||
if len(host) == 0 { | |||
continue | |||
} | |||
if strings.Contains(host, "/") { | |||
// We assume that it's a CIDR address like 127.0.0.0/8 | |||
if _, net, err := net.ParseCIDR(host); err == nil { | |||
p.AddNetwork(net) | |||
} | |||
continue | |||
} | |||
if ip := net.ParseIP(host); ip != nil { | |||
p.AddIP(ip) | |||
continue | |||
} | |||
if strings.HasPrefix(host, "*.") { | |||
p.AddZone(host[1:]) | |||
continue | |||
} | |||
p.AddHost(host) | |||
} | |||
} | |||
// AddIP specifies an IP address that will use the bypass proxy. Note that | |||
// this will only take effect if a literal IP address is dialed. A connection | |||
// to a named host will never match an IP. | |||
func (p *PerHost) AddIP(ip net.IP) { | |||
p.bypassIPs = append(p.bypassIPs, ip) | |||
} | |||
// AddNetwork specifies an IP range that will use the bypass proxy. Note that | |||
// this will only take effect if a literal IP address is dialed. A connection | |||
// to a named host will never match. | |||
func (p *PerHost) AddNetwork(net *net.IPNet) { | |||
p.bypassNetworks = append(p.bypassNetworks, net) | |||
} | |||
// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of | |||
// "example.com" matches "example.com" and all of its subdomains. | |||
func (p *PerHost) AddZone(zone string) { | |||
if strings.HasSuffix(zone, ".") { | |||
zone = zone[:len(zone)-1] | |||
} | |||
if !strings.HasPrefix(zone, ".") { | |||
zone = "." + zone | |||
} | |||
p.bypassZones = append(p.bypassZones, zone) | |||
} | |||
// AddHost specifies a host name that will use the bypass proxy. | |||
func (p *PerHost) AddHost(host string) { | |||
if strings.HasSuffix(host, ".") { | |||
host = host[:len(host)-1] | |||
} | |||
p.bypassHosts = append(p.bypassHosts, host) | |||
} |
@ -0,0 +1,149 @@ | |||
// Copyright 2011 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. | |||
// Package proxy provides support for a variety of protocols to proxy network | |||
// data. | |||
package proxy // import "golang.org/x/net/proxy" | |||
import ( | |||
"errors" | |||
"net" | |||
"net/url" | |||
"os" | |||
"sync" | |||
) | |||
// A Dialer is a means to establish a connection. | |||
// Custom dialers should also implement ContextDialer. | |||
type Dialer interface { | |||
// Dial connects to the given address via the proxy. | |||
Dial(network, addr string) (c net.Conn, err error) | |||
} | |||
// Auth contains authentication parameters that specific Dialers may require. | |||
type Auth struct { | |||
User, Password string | |||
} | |||
// FromEnvironment returns the dialer specified by the proxy-related | |||
// variables in the environment and makes underlying connections | |||
// directly. | |||
func FromEnvironment() Dialer { | |||
return FromEnvironmentUsing(Direct) | |||
} | |||
// FromEnvironmentUsing returns the dialer specify by the proxy-related | |||
// variables in the environment and makes underlying connections | |||
// using the provided forwarding Dialer (for instance, a *net.Dialer | |||
// with desired configuration). | |||
func FromEnvironmentUsing(forward Dialer) Dialer { | |||
allProxy := allProxyEnv.Get() | |||
if len(allProxy) == 0 { | |||
return forward | |||
} | |||
proxyURL, err := url.Parse(allProxy) | |||
if err != nil { | |||
return forward | |||
} | |||
proxy, err := FromURL(proxyURL, forward) | |||
if err != nil { | |||
return forward | |||
} | |||
noProxy := noProxyEnv.Get() | |||
if len(noProxy) == 0 { | |||
return proxy | |||
} | |||
perHost := NewPerHost(proxy, forward) | |||
perHost.AddFromString(noProxy) | |||
return perHost | |||
} | |||
// proxySchemes is a map from URL schemes to a function that creates a Dialer | |||
// from a URL with such a scheme. | |||
var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error) | |||
// RegisterDialerType takes a URL scheme and a function to generate Dialers from | |||
// a URL with that scheme and a forwarding Dialer. Registered schemes are used | |||
// by FromURL. | |||
func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) { | |||
if proxySchemes == nil { | |||
proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error)) | |||
} | |||
proxySchemes[scheme] = f | |||
} | |||
// FromURL returns a Dialer given a URL specification and an underlying | |||
// Dialer for it to make network requests. | |||
func FromURL(u *url.URL, forward Dialer) (Dialer, error) { | |||
var auth *Auth | |||
if u.User != nil { | |||
auth = new(Auth) | |||
auth.User = u.User.Username() | |||
if p, ok := u.User.Password(); ok { | |||
auth.Password = p | |||
} | |||
} | |||
switch u.Scheme { | |||
case "socks5", "socks5h": | |||
addr := u.Hostname() | |||
port := u.Port() | |||
if port == "" { | |||
port = "1080" | |||
} | |||
return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward) | |||
} | |||
// If the scheme doesn't match any of the built-in schemes, see if it | |||
// was registered by another package. | |||
if proxySchemes != nil { | |||
if f, ok := proxySchemes[u.Scheme]; ok { | |||
return f(u, forward) | |||
} | |||
} | |||
return nil, errors.New("proxy: unknown scheme: " + u.Scheme) | |||
} | |||
var ( | |||
allProxyEnv = &envOnce{ | |||
names: []string{"ALL_PROXY", "all_proxy"}, | |||
} | |||
noProxyEnv = &envOnce{ | |||
names: []string{"NO_PROXY", "no_proxy"}, | |||
} | |||
) | |||
// envOnce looks up an environment variable (optionally by multiple | |||
// names) once. It mitigates expensive lookups on some platforms | |||
// (e.g. Windows). | |||
// (Borrowed from net/http/transport.go) | |||
type envOnce struct { | |||
names []string | |||
once sync.Once | |||
val string | |||
} | |||
func (e *envOnce) Get() string { | |||
e.once.Do(e.init) | |||
return e.val | |||
} | |||
func (e *envOnce) init() { | |||
for _, n := range e.names { | |||
e.val = os.Getenv(n) | |||
if e.val != "" { | |||
return | |||
} | |||
} | |||
} | |||
// reset is used by tests | |||
func (e *envOnce) reset() { | |||
e.once = sync.Once{} | |||
e.val = "" | |||
} |
@ -0,0 +1,42 @@ | |||
// Copyright 2011 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. | |||
package proxy | |||
import ( | |||
"context" | |||
"net" | |||
"golang.org/x/net/internal/socks" | |||
) | |||
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given | |||
// address with an optional username and password. | |||
// See RFC 1928 and RFC 1929. | |||
func SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) { | |||
d := socks.NewDialer(network, address) | |||
if forward != nil { | |||
if f, ok := forward.(ContextDialer); ok { | |||
d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) { | |||
return f.DialContext(ctx, network, address) | |||
} | |||
} else { | |||
d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) { | |||
return dialContext(ctx, forward, network, address) | |||
} | |||
} | |||
} | |||
if auth != nil { | |||
up := socks.UsernamePassword{ | |||
Username: auth.User, | |||
Password: auth.Password, | |||
} | |||
d.AuthMethods = []socks.AuthMethod{ | |||
socks.AuthMethodNotRequired, | |||
socks.AuthMethodUsernamePassword, | |||
} | |||
d.Authenticate = up.Authenticate | |||
} | |||
return d, nil | |||
} |
@ -0,0 +1,17 @@ | |||
// Copyright 2018 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go | |||
// | |||
TEXT ·syscall6(SB),NOSPLIT,$0-88 | |||
JMP syscall·syscall6(SB) | |||
TEXT ·rawSyscall6(SB),NOSPLIT,$0-88 | |||
JMP syscall·rawSyscall6(SB) |
@ -0,0 +1,36 @@ | |||
// Copyright 2019 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. | |||
// Minimal copy of x/sys/unix so the cpu package can make a | |||
// system call on AIX without depending on x/sys/unix. | |||
// (See golang.org/issue/32102) | |||
// +build aix,ppc64 | |||
// +build !gccgo | |||
package cpu | |||
import ( | |||
"syscall" | |||
"unsafe" | |||
) | |||
//go:cgo_import_dynamic libc_getsystemcfg getsystemcfg "libc.a/shr_64.o" | |||
//go:linkname libc_getsystemcfg libc_getsystemcfg | |||
type syscallFunc uintptr | |||
var libc_getsystemcfg syscallFunc | |||
type errno = syscall.Errno | |||
// Implemented in runtime/syscall_aix.go. | |||
func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno) | |||
func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno) | |||
func callgetsystemcfg(label int) (r1 uintptr, e1 errno) { | |||
r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getsystemcfg)), 1, uintptr(label), 0, 0, 0, 0, 0) | |||
return | |||
} |
@ -0,0 +1,54 @@ | |||
// Copyright 2019 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. | |||
// +build riscv64,!gccgo | |||
#include "textflag.h" | |||
// | |||
// System calls for linux/riscv64. | |||
// | |||
// Where available, just jump to package syscall's implementation of | |||
// these functions. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
JMP syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
JMP syscall·Syscall6(SB) | |||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48 | |||
CALL runtime·entersyscall(SB) | |||
MOV a1+8(FP), A0 | |||
MOV a2+16(FP), A1 | |||
MOV a3+24(FP), A2 | |||
MOV $0, A3 | |||
MOV $0, A4 | |||
MOV $0, A5 | |||
MOV $0, A6 | |||
MOV trap+0(FP), A7 // syscall entry | |||
ECALL | |||
MOV A0, r1+32(FP) // r1 | |||
MOV A1, r2+40(FP) // r2 | |||
CALL runtime·exitsyscall(SB) | |||
RET | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
JMP syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
JMP syscall·RawSyscall6(SB) | |||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48 | |||
MOV a1+8(FP), A0 | |||
MOV a2+16(FP), A1 | |||
MOV a3+24(FP), A2 | |||
MOV ZERO, A3 | |||
MOV ZERO, A4 | |||
MOV ZERO, A5 | |||
MOV trap+0(FP), A7 // syscall entry | |||
ECALL | |||
MOV A0, r1+32(FP) | |||
MOV A1, r2+40(FP) | |||
RET |
@ -0,0 +1,29 @@ | |||
// Copyright 2019 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System call support for arm64, OpenBSD | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
JMP syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
JMP syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
JMP syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
JMP syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
JMP syscall·RawSyscall6(SB) |
@ -0,0 +1,355 @@ | |||
// Copyright 2019 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. | |||
// +build ignore | |||
// Parse the header files for OpenBSD and generate a Go usable sysctl MIB. | |||
// | |||
// Build a MIB with each entry being an array containing the level, type and | |||
// a hash that will contain additional entries if the current entry is a node. | |||
// We then walk this MIB and create a flattened sysctl name to OID hash. | |||
package main | |||
import ( | |||
"bufio" | |||
"fmt" | |||
"os" | |||
"path/filepath" | |||
"regexp" | |||
"sort" | |||
"strings" | |||
) | |||
var ( | |||
goos, goarch string | |||
) | |||
// cmdLine returns this programs's commandline arguments. | |||
func cmdLine() string { | |||
return "go run mksysctl_openbsd.go " + strings.Join(os.Args[1:], " ") | |||
} | |||
// buildTags returns build tags. | |||
func buildTags() string { | |||
return fmt.Sprintf("%s,%s", goarch, goos) | |||
} | |||
// reMatch performs regular expression match and stores the substring slice to value pointed by m. | |||
func reMatch(re *regexp.Regexp, str string, m *[]string) bool { | |||
*m = re.FindStringSubmatch(str) | |||
if *m != nil { | |||
return true | |||
} | |||
return false | |||
} | |||
type nodeElement struct { | |||
n int | |||
t string | |||
pE *map[string]nodeElement | |||
} | |||
var ( | |||
debugEnabled bool | |||
mib map[string]nodeElement | |||
node *map[string]nodeElement | |||
nodeMap map[string]string | |||
sysCtl []string | |||
) | |||
var ( | |||
ctlNames1RE = regexp.MustCompile(`^#define\s+(CTL_NAMES)\s+{`) | |||
ctlNames2RE = regexp.MustCompile(`^#define\s+(CTL_(.*)_NAMES)\s+{`) | |||
ctlNames3RE = regexp.MustCompile(`^#define\s+((.*)CTL_NAMES)\s+{`) | |||
netInetRE = regexp.MustCompile(`^netinet/`) | |||
netInet6RE = regexp.MustCompile(`^netinet6/`) | |||
netRE = regexp.MustCompile(`^net/`) | |||
bracesRE = regexp.MustCompile(`{.*}`) | |||
ctlTypeRE = regexp.MustCompile(`{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}`) | |||
fsNetKernRE = regexp.MustCompile(`^(fs|net|kern)_`) | |||
) | |||
func debug(s string) { | |||
if debugEnabled { | |||
fmt.Fprintln(os.Stderr, s) | |||
} | |||
} | |||
// Walk the MIB and build a sysctl name to OID mapping. | |||
func buildSysctl(pNode *map[string]nodeElement, name string, oid []int) { | |||
lNode := pNode // local copy of pointer to node | |||
var keys []string | |||
for k := range *lNode { | |||
keys = append(keys, k) | |||
} | |||
sort.Strings(keys) | |||
for _, key := range keys { | |||
nodename := name | |||
if name != "" { | |||
nodename += "." | |||
} | |||
nodename += key | |||
nodeoid := append(oid, (*pNode)[key].n) | |||
if (*pNode)[key].t == `CTLTYPE_NODE` { | |||
if _, ok := nodeMap[nodename]; ok { | |||
lNode = &mib | |||
ctlName := nodeMap[nodename] | |||
for _, part := range strings.Split(ctlName, ".") { | |||
lNode = ((*lNode)[part]).pE | |||
} | |||
} else { | |||
lNode = (*pNode)[key].pE | |||
} | |||
buildSysctl(lNode, nodename, nodeoid) | |||
} else if (*pNode)[key].t != "" { | |||
oidStr := []string{} | |||
for j := range nodeoid { | |||
oidStr = append(oidStr, fmt.Sprintf("%d", nodeoid[j])) | |||
} | |||
text := "\t{ \"" + nodename + "\", []_C_int{ " + strings.Join(oidStr, ", ") + " } }, \n" | |||
sysCtl = append(sysCtl, text) | |||
} | |||
} | |||
} | |||
func main() { | |||
// Get the OS (using GOOS_TARGET if it exist) | |||
goos = os.Getenv("GOOS_TARGET") | |||
if goos == "" { | |||
goos = os.Getenv("GOOS") | |||
} | |||
// Get the architecture (using GOARCH_TARGET if it exists) | |||
goarch = os.Getenv("GOARCH_TARGET") | |||
if goarch == "" { | |||
goarch = os.Getenv("GOARCH") | |||
} | |||
// Check if GOOS and GOARCH environment variables are defined | |||
if goarch == "" || goos == "" { | |||
fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n") | |||
os.Exit(1) | |||
} | |||
mib = make(map[string]nodeElement) | |||
headers := [...]string{ | |||
`sys/sysctl.h`, | |||
`sys/socket.h`, | |||
`sys/tty.h`, | |||
`sys/malloc.h`, | |||
`sys/mount.h`, | |||
`sys/namei.h`, | |||
`sys/sem.h`, | |||
`sys/shm.h`, | |||
`sys/vmmeter.h`, | |||
`uvm/uvmexp.h`, | |||
`uvm/uvm_param.h`, | |||
`uvm/uvm_swap_encrypt.h`, | |||
`ddb/db_var.h`, | |||
`net/if.h`, | |||
`net/if_pfsync.h`, | |||
`net/pipex.h`, | |||
`netinet/in.h`, | |||
`netinet/icmp_var.h`, | |||
`netinet/igmp_var.h`, | |||
`netinet/ip_ah.h`, | |||
`netinet/ip_carp.h`, | |||
`netinet/ip_divert.h`, | |||
`netinet/ip_esp.h`, | |||
`netinet/ip_ether.h`, | |||
`netinet/ip_gre.h`, | |||
`netinet/ip_ipcomp.h`, | |||
`netinet/ip_ipip.h`, | |||
`netinet/pim_var.h`, | |||
`netinet/tcp_var.h`, | |||
`netinet/udp_var.h`, | |||
`netinet6/in6.h`, | |||
`netinet6/ip6_divert.h`, | |||
`netinet6/pim6_var.h`, | |||
`netinet/icmp6.h`, | |||
`netmpls/mpls.h`, | |||
} | |||
ctls := [...]string{ | |||
`kern`, | |||
`vm`, | |||
`fs`, | |||
`net`, | |||
//debug /* Special handling required */ | |||
`hw`, | |||
//machdep /* Arch specific */ | |||
`user`, | |||
`ddb`, | |||
//vfs /* Special handling required */ | |||
`fs.posix`, | |||
`kern.forkstat`, | |||
`kern.intrcnt`, | |||
`kern.malloc`, | |||
`kern.nchstats`, | |||
`kern.seminfo`, | |||
`kern.shminfo`, | |||
`kern.timecounter`, | |||
`kern.tty`, | |||
`kern.watchdog`, | |||
`net.bpf`, | |||
`net.ifq`, | |||
`net.inet`, | |||
`net.inet.ah`, | |||
`net.inet.carp`, | |||
`net.inet.divert`, | |||
`net.inet.esp`, | |||
`net.inet.etherip`, | |||
`net.inet.gre`, | |||
`net.inet.icmp`, | |||
`net.inet.igmp`, | |||
`net.inet.ip`, | |||
`net.inet.ip.ifq`, | |||
`net.inet.ipcomp`, | |||
`net.inet.ipip`, | |||
`net.inet.mobileip`, | |||
`net.inet.pfsync`, | |||
`net.inet.pim`, | |||
`net.inet.tcp`, | |||
`net.inet.udp`, | |||
`net.inet6`, | |||
`net.inet6.divert`, | |||
`net.inet6.ip6`, | |||
`net.inet6.icmp6`, | |||
`net.inet6.pim6`, | |||
`net.inet6.tcp6`, | |||
`net.inet6.udp6`, | |||
`net.mpls`, | |||
`net.mpls.ifq`, | |||
`net.key`, | |||
`net.pflow`, | |||
`net.pfsync`, | |||
`net.pipex`, | |||
`net.rt`, | |||
`vm.swapencrypt`, | |||
//vfsgenctl /* Special handling required */ | |||
} | |||
// Node name "fixups" | |||
ctlMap := map[string]string{ | |||
"ipproto": "net.inet", | |||
"net.inet.ipproto": "net.inet", | |||
"net.inet6.ipv6proto": "net.inet6", | |||
"net.inet6.ipv6": "net.inet6.ip6", | |||
"net.inet.icmpv6": "net.inet6.icmp6", | |||
"net.inet6.divert6": "net.inet6.divert", | |||
"net.inet6.tcp6": "net.inet.tcp", | |||
"net.inet6.udp6": "net.inet.udp", | |||
"mpls": "net.mpls", | |||
"swpenc": "vm.swapencrypt", | |||
} | |||
// Node mappings | |||
nodeMap = map[string]string{ | |||
"net.inet.ip.ifq": "net.ifq", | |||
"net.inet.pfsync": "net.pfsync", | |||
"net.mpls.ifq": "net.ifq", | |||
} | |||
mCtls := make(map[string]bool) | |||
for _, ctl := range ctls { | |||
mCtls[ctl] = true | |||
} | |||
for _, header := range headers { | |||
debug("Processing " + header) | |||
file, err := os.Open(filepath.Join("/usr/include", header)) | |||
if err != nil { | |||
fmt.Fprintf(os.Stderr, "%v\n", err) | |||
os.Exit(1) | |||
} | |||
s := bufio.NewScanner(file) | |||
for s.Scan() { | |||
var sub []string | |||
if reMatch(ctlNames1RE, s.Text(), &sub) || | |||
reMatch(ctlNames2RE, s.Text(), &sub) || | |||
reMatch(ctlNames3RE, s.Text(), &sub) { | |||
if sub[1] == `CTL_NAMES` { | |||
// Top level. | |||
node = &mib | |||
} else { | |||
// Node. | |||
nodename := strings.ToLower(sub[2]) | |||
ctlName := "" | |||
if reMatch(netInetRE, header, &sub) { | |||
ctlName = "net.inet." + nodename | |||
} else if reMatch(netInet6RE, header, &sub) { | |||
ctlName = "net.inet6." + nodename | |||
} else if reMatch(netRE, header, &sub) { | |||
ctlName = "net." + nodename | |||
} else { | |||
ctlName = nodename | |||
ctlName = fsNetKernRE.ReplaceAllString(ctlName, `$1.`) | |||
} | |||
if val, ok := ctlMap[ctlName]; ok { | |||
ctlName = val | |||
} | |||
if _, ok := mCtls[ctlName]; !ok { | |||
debug("Ignoring " + ctlName + "...") | |||
continue | |||
} | |||
// Walk down from the top of the MIB. | |||
node = &mib | |||
for _, part := range strings.Split(ctlName, ".") { | |||
if _, ok := (*node)[part]; !ok { | |||
debug("Missing node " + part) | |||
(*node)[part] = nodeElement{n: 0, t: "", pE: &map[string]nodeElement{}} | |||
} | |||
node = (*node)[part].pE | |||
} | |||
} | |||
// Populate current node with entries. | |||
i := -1 | |||
for !strings.HasPrefix(s.Text(), "}") { | |||
s.Scan() | |||
if reMatch(bracesRE, s.Text(), &sub) { | |||
i++ | |||
} | |||
if !reMatch(ctlTypeRE, s.Text(), &sub) { | |||
continue | |||
} | |||
(*node)[sub[1]] = nodeElement{n: i, t: sub[2], pE: &map[string]nodeElement{}} | |||
} | |||
} | |||
} | |||
err = s.Err() | |||
if err != nil { | |||
fmt.Fprintf(os.Stderr, "%v\n", err) | |||
os.Exit(1) | |||
} | |||
file.Close() | |||
} | |||
buildSysctl(&mib, "", []int{}) | |||
sort.Strings(sysCtl) | |||
text := strings.Join(sysCtl, "") | |||
fmt.Printf(srcTemplate, cmdLine(), buildTags(), text) | |||
} | |||
const srcTemplate = `// %s | |||
// Code generated by the command above; DO NOT EDIT. | |||
// +build %s | |||
package unix | |||
type mibentry struct { | |||
ctlname string | |||
ctloid []_C_int | |||
} | |||
var sysctlMib = []mibentry { | |||
%s | |||
} | |||
` |
@ -1,265 +0,0 @@ | |||
#!/usr/bin/env perl | |||
# Copyright 2011 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. | |||
# | |||
# Parse the header files for OpenBSD and generate a Go usable sysctl MIB. | |||
# | |||
# Build a MIB with each entry being an array containing the level, type and | |||
# a hash that will contain additional entries if the current entry is a node. | |||
# We then walk this MIB and create a flattened sysctl name to OID hash. | |||
# | |||
use strict; | |||
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { | |||
print STDERR "GOARCH or GOOS not defined in environment\n"; | |||
exit 1; | |||
} | |||
my $debug = 0; | |||
my %ctls = (); | |||
my @headers = qw ( | |||
sys/sysctl.h | |||
sys/socket.h | |||
sys/tty.h | |||
sys/malloc.h | |||
sys/mount.h | |||
sys/namei.h | |||
sys/sem.h | |||
sys/shm.h | |||
sys/vmmeter.h | |||
uvm/uvmexp.h | |||
uvm/uvm_param.h | |||
uvm/uvm_swap_encrypt.h | |||
ddb/db_var.h | |||
net/if.h | |||
net/if_pfsync.h | |||
net/pipex.h | |||
netinet/in.h | |||
netinet/icmp_var.h | |||
netinet/igmp_var.h | |||
netinet/ip_ah.h | |||
netinet/ip_carp.h | |||
netinet/ip_divert.h | |||
netinet/ip_esp.h | |||
netinet/ip_ether.h | |||
netinet/ip_gre.h | |||
netinet/ip_ipcomp.h | |||
netinet/ip_ipip.h | |||
netinet/pim_var.h | |||
netinet/tcp_var.h | |||
netinet/udp_var.h | |||
netinet6/in6.h | |||
netinet6/ip6_divert.h | |||
netinet6/pim6_var.h | |||
netinet/icmp6.h | |||
netmpls/mpls.h | |||
); | |||
my @ctls = qw ( | |||
kern | |||
vm | |||
fs | |||
net | |||
#debug # Special handling required | |||
hw | |||
#machdep # Arch specific | |||
user | |||
ddb | |||
#vfs # Special handling required | |||
fs.posix | |||
kern.forkstat | |||
kern.intrcnt | |||
kern.malloc | |||
kern.nchstats | |||
kern.seminfo | |||
kern.shminfo | |||
kern.timecounter | |||
kern.tty | |||
kern.watchdog | |||
net.bpf | |||
net.ifq | |||
net.inet | |||
net.inet.ah | |||
net.inet.carp | |||
net.inet.divert | |||
net.inet.esp | |||
net.inet.etherip | |||
net.inet.gre | |||
net.inet.icmp | |||
net.inet.igmp | |||
net.inet.ip | |||
net.inet.ip.ifq | |||
net.inet.ipcomp | |||
net.inet.ipip | |||
net.inet.mobileip | |||
net.inet.pfsync | |||
net.inet.pim | |||
net.inet.tcp | |||
net.inet.udp | |||
net.inet6 | |||
net.inet6.divert | |||
net.inet6.ip6 | |||
net.inet6.icmp6 | |||
net.inet6.pim6 | |||
net.inet6.tcp6 | |||
net.inet6.udp6 | |||
net.mpls | |||
net.mpls.ifq | |||
net.key | |||
net.pflow | |||
net.pfsync | |||
net.pipex | |||
net.rt | |||
vm.swapencrypt | |||
#vfsgenctl # Special handling required | |||
); | |||
# Node name "fixups" | |||
my %ctl_map = ( | |||
"ipproto" => "net.inet", | |||
"net.inet.ipproto" => "net.inet", | |||
"net.inet6.ipv6proto" => "net.inet6", | |||
"net.inet6.ipv6" => "net.inet6.ip6", | |||
"net.inet.icmpv6" => "net.inet6.icmp6", | |||
"net.inet6.divert6" => "net.inet6.divert", | |||
"net.inet6.tcp6" => "net.inet.tcp", | |||
"net.inet6.udp6" => "net.inet.udp", | |||
"mpls" => "net.mpls", | |||
"swpenc" => "vm.swapencrypt" | |||
); | |||
# Node mappings | |||
my %node_map = ( | |||
"net.inet.ip.ifq" => "net.ifq", | |||
"net.inet.pfsync" => "net.pfsync", | |||
"net.mpls.ifq" => "net.ifq" | |||
); | |||
my $ctlname; | |||
my %mib = (); | |||
my %sysctl = (); | |||
my $node; | |||
sub debug() { | |||
print STDERR "$_[0]\n" if $debug; | |||
} | |||
# Walk the MIB and build a sysctl name to OID mapping. | |||
sub build_sysctl() { | |||
my ($node, $name, $oid) = @_; | |||
my %node = %{$node}; | |||
my @oid = @{$oid}; | |||
foreach my $key (sort keys %node) { | |||
my @node = @{$node{$key}}; | |||
my $nodename = $name.($name ne '' ? '.' : '').$key; | |||
my @nodeoid = (@oid, $node[0]); | |||
if ($node[1] eq 'CTLTYPE_NODE') { | |||
if (exists $node_map{$nodename}) { | |||
$node = \%mib; | |||
$ctlname = $node_map{$nodename}; | |||
foreach my $part (split /\./, $ctlname) { | |||
$node = \%{@{$$node{$part}}[2]}; | |||
} | |||
} else { | |||
$node = $node[2]; | |||
} | |||
&build_sysctl($node, $nodename, \@nodeoid); | |||
} elsif ($node[1] ne '') { | |||
$sysctl{$nodename} = \@nodeoid; | |||
} | |||
} | |||
} | |||
foreach my $ctl (@ctls) { | |||
$ctls{$ctl} = $ctl; | |||
} | |||
# Build MIB | |||
foreach my $header (@headers) { | |||
&debug("Processing $header..."); | |||
open HEADER, "/usr/include/$header" || | |||
print STDERR "Failed to open $header\n"; | |||
while (<HEADER>) { | |||
if ($_ =~ /^#define\s+(CTL_NAMES)\s+{/ || | |||
$_ =~ /^#define\s+(CTL_(.*)_NAMES)\s+{/ || | |||
$_ =~ /^#define\s+((.*)CTL_NAMES)\s+{/) { | |||
if ($1 eq 'CTL_NAMES') { | |||
# Top level. | |||
$node = \%mib; | |||
} else { | |||
# Node. | |||
my $nodename = lc($2); | |||
if ($header =~ /^netinet\//) { | |||
$ctlname = "net.inet.$nodename"; | |||
} elsif ($header =~ /^netinet6\//) { | |||
$ctlname = "net.inet6.$nodename"; | |||
} elsif ($header =~ /^net\//) { | |||
$ctlname = "net.$nodename"; | |||
} else { | |||
$ctlname = "$nodename"; | |||
$ctlname =~ s/^(fs|net|kern)_/$1\./; | |||
} | |||
if (exists $ctl_map{$ctlname}) { | |||
$ctlname = $ctl_map{$ctlname}; | |||
} | |||
if (not exists $ctls{$ctlname}) { | |||
&debug("Ignoring $ctlname..."); | |||
next; | |||
} | |||
# Walk down from the top of the MIB. | |||
$node = \%mib; | |||
foreach my $part (split /\./, $ctlname) { | |||
if (not exists $$node{$part}) { | |||
&debug("Missing node $part"); | |||
$$node{$part} = [ 0, '', {} ]; | |||
} | |||
$node = \%{@{$$node{$part}}[2]}; | |||
} | |||
} | |||
# Populate current node with entries. | |||
my $i = -1; | |||
while (defined($_) && $_ !~ /^}/) { | |||
$_ = <HEADER>; | |||
$i++ if $_ =~ /{.*}/; | |||
next if $_ !~ /{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}/; | |||
$$node{$1} = [ $i, $2, {} ]; | |||
} | |||
} | |||
} | |||
close HEADER; | |||
} | |||
&build_sysctl(\%mib, "", []); | |||
print <<EOF; | |||
// mksysctl_openbsd.pl | |||
// Code generated by the command above; DO NOT EDIT. | |||
// +build $ENV{'GOARCH'},$ENV{'GOOS'} | |||
package unix; | |||
type mibentry struct { | |||
ctlname string | |||
ctloid []_C_int | |||
} | |||
var sysctlMib = []mibentry { | |||
EOF | |||
foreach my $name (sort keys %sysctl) { | |||
my @oid = @{$sysctl{$name}}; | |||
print "\t{ \"$name\", []_C_int{ ", join(', ', @oid), " } }, \n"; | |||
} | |||
print <<EOF; | |||
} | |||
EOF |
@ -0,0 +1,37 @@ | |||
// Copyright 2019 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. | |||
// +build arm64,openbsd | |||
package unix | |||
func setTimespec(sec, nsec int64) Timespec { | |||
return Timespec{Sec: sec, Nsec: nsec} | |||
} | |||
func setTimeval(sec, usec int64) Timeval { | |||
return Timeval{Sec: sec, Usec: usec} | |||
} | |||
func SetKevent(k *Kevent_t, fd, mode, flags int) { | |||
k.Ident = uint64(fd) | |||
k.Filter = int16(mode) | |||
k.Flags = uint16(flags) | |||
} | |||
func (iov *Iovec) SetLen(length int) { | |||
iov.Len = uint64(length) | |||
} | |||
func (msghdr *Msghdr) SetControllen(length int) { | |||
msghdr.Controllen = uint32(length) | |||
} | |||
func (cmsg *Cmsghdr) SetLen(length int) { | |||
cmsg.Len = uint32(length) | |||
} | |||
// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions | |||
// of openbsd/amd64 the syscall is called sysctl instead of __sysctl. | |||
const SYS___SYSCTL = SYS_SYSCTL |