golang 通过ssh代理连接mysql的操作

我就废话不多说了,大家还是直接看代码吧~

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

package main

import (

"bytes"

"context"

"database/sql"

"errors"

"fmt"

"github.com/go-sql-driver/mysql"

"golang.org/x/crypto/ssh"

"io"

"io/ioutil"

"net"

"os"

)

type ViaSSHDialer struct {

client *ssh.Client

_ *context.Context

}

func (self *ViaSSHDialer) Dial(context context.Context,addr string) (net.Conn, error) {

return self.client.Dial("tcp", addr)

}

type remoteScriptType byte

type remoteShellType byte

const (

cmdLine remoteScriptType = iota

rawScript

scriptFile

interactiveShell remoteShellType = iota

nonInteractiveShell

)

type Client struct {

client *ssh.Client

}

func main() {

client, err := DialWithPasswd("ip:port", "user", "password")

if err != nil {

panic(err)

}

out, err := client.Cmd("ls -l").Output()

if err != nil {

panic(err)

}

fmt.Println(string(out))

// Now we register the ViaSSHDialer with the ssh connection as a parameter

mysql.RegisterDialContext("mysql+tcp", (&ViaSSHDialer{client.client,nil}).Dial)

//mysql.RegisterDial("mysql+tcp", (&ViaSSHDialer{client.client}).Dial)

if db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mysql+tcp(%s)/%s","Aiqitest", "uf6amk146d2aoemi7", "139.196.174.234:3306", "Aiqitest"));

err == nil {

fmt.Printf("Successfully connected to the db\n")

if rows, err := db.Query("SELECT id, name FROM table ORDER BY id"); err == nil {

for rows.Next() {

var id int64

var name string

rows.Scan(&id, &name)

fmt.Printf("ID: %d Name: %s\n", id, name)

}

rows.Close()

} else {

fmt.Printf("Failure: %s", err.Error())

}

db.Close()

}

}

// DialWithPasswd starts a client connection to the given SSH server with passwd authmethod.

func DialWithPasswd(addr, user, passwd string) (*Client, error) {

config := &ssh.ClientConfig{

User: user,

Auth: []ssh.AuthMethod{

ssh.Password(passwd),

},

HostKeyCallback: ssh.HostKeyCallback(func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }),

}

return Dial("tcp", addr, config)

}

// DialWithKey starts a client connection to the given SSH server with key authmethod.

func DialWithKey(addr, user, keyfile string) (*Client, error) {

key, err := ioutil.ReadFile(keyfile)

if err != nil {

return nil, err

}

signer, err := ssh.ParsePrivateKey(key)

if err != nil {

return nil, err

}

config := &ssh.ClientConfig{

User: user,

Auth: []ssh.AuthMethod{

ssh.PublicKeys(signer),

},

HostKeyCallback: ssh.HostKeyCallback(func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }),

}

return Dial("tcp", addr, config)

}

// DialWithKeyWithPassphrase same as DialWithKey but with a passphrase to decrypt the private key

func DialWithKeyWithPassphrase(addr, user, keyfile string, passphrase string) (*Client, error) {

key, err := ioutil.ReadFile(keyfile)

if err != nil {

return nil, err

}

signer, err := ssh.ParsePrivateKeyWithPassphrase(key, []byte(passphrase))

if err != nil {

return nil, err

}

config := &ssh.ClientConfig{

User: user,

Auth: []ssh.AuthMethod{

ssh.PublicKeys(signer),

},

HostKeyCallback: ssh.HostKeyCallback(func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }),

}

return Dial("tcp", addr, config)

}

// Dial starts a client connection to the given SSH server.

// This is wrap the ssh.Dial

func Dial(network, addr string, config *ssh.ClientConfig) (*Client, error) {

client, err := ssh.Dial(network, addr, config)

if err != nil {

return nil, err

}

return &Client{

client: client,

}, nil

}

func (c *Client) Close() error {

return c.client.Close()

}

// Cmd create a command on client

func (c *Client) Cmd(cmd string) *remoteScript {

return &remoteScript{

_type: cmdLine,

client: c.client,

script: bytes.NewBufferString(cmd + "\n"),

}

}

// Script

func (c *Client) Script(script string) *remoteScript {

return &remoteScript{

_type: rawScript,

client: c.client,

script: bytes.NewBufferString(script + "\n"),

}

}

// ScriptFile

func (c *Client) ScriptFile(fname string) *remoteScript {

return &remoteScript{

_type: scriptFile,

client: c.client,

scriptFile: fname,

}

}

type remoteScript struct {

client *ssh.Client

_type remoteScriptType

script *bytes.Buffer

scriptFile string

err error

stdout io.Writer

stderr io.Writer

}

// Run

func (rs *remoteScript) Run() error {

if rs.err != nil {

fmt.Println(rs.err)

return rs.err

}

if rs._type == cmdLine {

return rs.runCmds()

} else if rs._type == rawScript {

return rs.runScript()

} else if rs._type == scriptFile {

return rs.runScriptFile()

} else {

return errors.New("Not supported remoteScript type")

}

}

func (rs *remoteScript) Output() ([]byte, error) {

if rs.stdout != nil {

return nil, errors.New("Stdout already set")

}

var out bytes.Buffer

rs.stdout = &out

err := rs.Run()

return out.Bytes(), err

}

func (rs *remoteScript) SmartOutput() ([]byte, error) {

if rs.stdout != nil {

return nil, errors.New("Stdout already set")

}

if rs.stderr != nil {

return nil, errors.New("Stderr already set")

}

var (

stdout bytes.Buffer

stderr bytes.Buffer

)

rs.stdout = &stdout

rs.stderr = &stderr

err := rs.Run()

if err != nil {

return stderr.Bytes(), err

}

return stdout.Bytes(), err

}

func (rs *remoteScript) Cmd(cmd string) *remoteScript {

_, err := rs.script.WriteString(cmd + "\n")

if err != nil {

rs.err = err

}

return rs

}

func (rs *remoteScript) SetStdio(stdout, stderr io.Writer) *remoteScript {

rs.stdout = stdout

rs.stderr = stderr

return rs

}

func (rs *remoteScript) runCmd(cmd string) error {

session, err := rs.client.NewSession()

if err != nil {

return err

}

defer session.Close()

session.Stdout = rs.stdout

session.Stderr = rs.stderr

if err := session.Run(cmd); err != nil {

return err

}

return nil

}

func (rs *remoteScript) runCmds() error {

for {

statment, err := rs.script.ReadString('\n')

if err == io.EOF {

break

}

if err != nil {

return err

}

if err := rs.runCmd(statment); err != nil {

return err

}

}

return nil

}

func (rs *remoteScript) runScript() error {

session, err := rs.client.NewSession()

if err != nil {

return err

}

session.Stdin = rs.script

session.Stdout = rs.stdout

session.Stderr = rs.stderr

if err := session.Shell(); err != nil {

return err

}

if err := session.Wait(); err != nil {

return err

}

return nil

}

func (rs *remoteScript) runScriptFile() error {

var buffer bytes.Buffer

file, err := os.Open(rs.scriptFile)

if err != nil {

return err

}

_, err = io.Copy(&buffer, file)

if err != nil {

return err

}

rs.script = &buffer

return rs.runScript()

}

type remoteShell struct {

client *ssh.Client

requestPty bool

terminalConfig *TerminalConfig

stdin io.Reader

stdout io.Writer

stderr io.Writer

}

type TerminalConfig struct {

Term string

Hight int

Weight int

Modes ssh.TerminalModes

}

// Terminal create a interactive shell on client.

func (c *Client) Terminal(config *TerminalConfig) *remoteShell {

return &remoteShell{

client: c.client,

terminalConfig: config,

requestPty: true,

}

}

// Shell create a noninteractive shell on client.

func (c *Client) Shell() *remoteShell {

return &remoteShell{

client: c.client,

requestPty: false,

}

}

func (rs *remoteShell) SetStdio(stdin io.Reader, stdout, stderr io.Writer) *remoteShell {

rs.stdin = stdin

rs.stdout = stdout

rs.stderr = stderr

return rs

}

// Start start a remote shell on client

func (rs *remoteShell) Start() error {

session, err := rs.client.NewSession()

if err != nil {

return err

}

defer session.Close()

if rs.stdin == nil {

session.Stdin = os.Stdin

} else {

session.Stdin = rs.stdin

}

if rs.stdout == nil {

session.Stdout = os.Stdout

} else {

session.Stdout = rs.stdout

}

if rs.stderr == nil {

session.Stderr = os.Stderr

} else {

session.Stderr = rs.stderr

}

if rs.requestPty {

tc := rs.terminalConfig

if tc == nil {

tc = &TerminalConfig{

Term: "xterm",

Hight: 40,

Weight: 80,

}

}

if err := session.RequestPty(tc.Term, tc.Hight, tc.Weight, tc.Modes); err != nil {

return err

}

}

if err := session.Shell(); err != nil {

return err

}

if err := session.Wait(); err != nil {

return err

}

return nil

}

补充:用golang写socks5代理服务器2-ssh远程代理

上次用golang来实现本地socks5代理,然而使用代理当然是为了和谐上网,所以这次来介绍用ssh来实现远程代理,用到官方ssh包

用golang连接ssh并不难

读取密钥,设置配置,连接服务器就ok了(不建议用用户名+密码方式连接ssh)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

b, err := ioutil.ReadFile("/home/myml/.ssh/id_rsa")

if err != nil {

log.Println(err)

return

}

pKey, err := ssh.ParsePrivateKey(b)

if err != nil {

log.Println(err)

return

}

config := ssh.ClientConfig{

User: "userName",

Auth: []ssh.AuthMethod{

ssh.PublicKeys(pKey),

},

}

client, err = ssh.Dial("tcp", "Host:22", &config)

if err != nil {

log.Println(err)

return

}

log.Println("连接服务器成功")

defer client.Close()

这样你就得到了一个client,它有个Dial()函数用来创建socket连接,这个是在服务器上创建的,也就可以突破网络限制了,加上上次的sock5代理,把net.Dial改为client.Dial,就能让服务器来代理访问了

?

1

2

3

4

5

6

7

8

server, err := client.Dial("tcp", addr)

if err != nil {

log.Println(err)

return

}

conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})

go io.Copy(server, conn)

io.Copy(conn, server)

下面是能成功运行并进行远程代理的代码(在Chrome和proxychains测试),ssh服务器和配置信息要修改为自己的

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

// socks5ProxyProxy project main.go

package main

import (

"bytes"

"encoding/binary"

"fmt"

"io"

"io/ioutil"

"log"

"net"

"golang.org/x/crypto/ssh"

)

func socks5Proxy(conn net.Conn) {

defer conn.Close()

var b [1024]byte

n, err := conn.Read(b[:])

if err != nil {

log.Println(err)

return

}

log.Printf("% x", b[:n])

conn.Write([]byte{0x05, 0x00})

n, err = conn.Read(b[:])

if err != nil {

log.Println(err)

return

}

log.Printf("% x", b[:n])

var addr string

switch b[3] {

case 0x01:

sip := sockIP{}

if err := binary.Read(bytes.NewReader(b[4:n]), binary.BigEndian, &sip); err != nil {

log.Println("请求解析错误")

return

}

addr = sip.toAddr()

case 0x03:

host := string(b[5 : n-2])

var port uint16

err = binary.Read(bytes.NewReader(b[n-2:n]), binary.BigEndian, &port)

if err != nil {

log.Println(err)

return

}

addr = fmt.Sprintf("%s:%d", host, port)

}

server, err := client.Dial("tcp", addr)

if err != nil {

log.Println(err)

return

}

conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})

go io.Copy(server, conn)

io.Copy(conn, server)

}

type sockIP struct {

A, B, C, D byte

PORT uint16

}

func (ip sockIP) toAddr() string {

return fmt.Sprintf("%d.%d.%d.%d:%d", ip.A, ip.B, ip.C, ip.D, ip.PORT)

}

func socks5ProxyStart() {

log.SetFlags(log.Ltime | log.Lshortfile)

server, err := net.Listen("tcp", ":8080")

if err != nil {

log.Panic(err)

}

defer server.Close()

log.Println("开始接受连接")

for {

client, err := server.Accept()

if err != nil {

log.Println(err)

return

}

log.Println("一个新连接")

go socks5Proxy(client)

}

}

var client *ssh.Client

func main() {

b, err := ioutil.ReadFile("/home/myml/.ssh/id_rsa")

if err != nil {

log.Println(err)

return

}

pKey, err := ssh.ParsePrivateKey(b)

if err != nil {

log.Println(err)

return

}

config := ssh.ClientConfig{

User: "user",

Auth: []ssh.AuthMethod{

ssh.PublicKeys(pKey),

},

}

client, err = ssh.Dial("tcp", "host:22", &config)

if err != nil {

log.Println(err)

return

}

log.Println("连接服务器成功")

defer client.Close()

client.Dial()

socks5ProxyStart()

return

}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。如有错误或未考虑完全的地方,望不吝赐教。

原文链接:https://blog.csdn.net/a1658616397/article/details/100890414

本文链接:https://my.lmcjl.com/post/14949.html

展开阅读全文

4 评论

留下您的评论.