mirror of https://gogs.blitter.com/RLabs/xs
				
				
				
			Cleaned up error handling in hkexnet.Conn.Read() a bit
This commit is contained in:
		
							parent
							
								
									e75ed159f6
								
							
						
					
					
						commit
						fcbdb77c79
					
				|  | @ -685,10 +685,8 @@ func (hl *HKExListener) Accept() (hc Conn, err error) { | ||||||
| //
 | //
 | ||||||
| // See go doc io.Reader
 | // See go doc io.Reader
 | ||||||
| func (hc Conn) Read(b []byte) (n int, err error) { | func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 	//log.Printf("[Decrypting...]\r\n")
 |  | ||||||
| 	for { | 	for { | ||||||
| 		//log.Printf("hc.dBuf.Len(): %d\n", hc.dBuf.Len())
 | 		if hc.dBuf.Len() > 0 { | ||||||
| 		if hc.dBuf.Len() > 0 /* len(b) */ { |  | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -698,31 +696,52 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 
 | 
 | ||||||
| 		// Read ctrl/status opcode (CSOHmacInvalid on hmac mismatch)
 | 		// Read ctrl/status opcode (CSOHmacInvalid on hmac mismatch)
 | ||||||
| 		err = binary.Read(*hc.c, binary.BigEndian, &ctrlStatOp) | 		err = binary.Read(*hc.c, binary.BigEndian, &ctrlStatOp) | ||||||
|  | 		if err != nil { | ||||||
|  | 			if err.Error() == "EOF" { | ||||||
|  | 				return 0, io.EOF | ||||||
|  | 			} | ||||||
|  | 			if strings.HasSuffix(err.Error(), "use of closed network connection") { | ||||||
|  | 				logger.LogNotice(fmt.Sprintln("[Client hung up]")) | ||||||
|  | 				return 0, io.EOF | ||||||
|  | 			} | ||||||
|  | 			etxt := fmt.Sprintf("** Failed read:%s (%s) **", "ctrlStatOp", err) | ||||||
|  | 			logger.LogErr(etxt) | ||||||
|  | 			return 0, errors.New(etxt) | ||||||
|  | 		} | ||||||
| 		log.Printf("[ctrlStatOp: %v]\n", ctrlStatOp) | 		log.Printf("[ctrlStatOp: %v]\n", ctrlStatOp) | ||||||
| 		if ctrlStatOp == CSOHmacInvalid { | 		if ctrlStatOp == CSOHmacInvalid { | ||||||
| 			// Other side indicated channel tampering, close channel
 | 			// Other side indicated channel tampering, close channel
 | ||||||
| 			hc.Close() | 			hc.Close() | ||||||
| 			return 1, errors.New("** ALERT - remote end detected HMAC mismatch - possible channel tampering **") | 			return 0, errors.New("** ALERT - remote end detected HMAC mismatch - possible channel tampering **") | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Read the hmac and payload len first
 | 		// Read the hmac and payload len first
 | ||||||
| 		err = binary.Read(*hc.c, binary.BigEndian, &hmacIn) | 		err = binary.Read(*hc.c, binary.BigEndian, &hmacIn) | ||||||
| 		// Normal client 'exit' from interactive session will cause
 |  | ||||||
| 		// (on server side) err.Error() == "<iface/addr info ...>: use of closed network connection"
 |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			if err == io.EOF || strings.HasSuffix(err.Error(), "use of closed network connection") { | 			if err.Error() == "EOF" { | ||||||
| 				logger.LogNotice(fmt.Sprintln("[Client hung up]")) | 				return 0, io.EOF | ||||||
| 			} else { |  | ||||||
| 				log.Println(err) |  | ||||||
| 			} | 			} | ||||||
| 			return 0, err | 			if strings.HasSuffix(err.Error(), "use of closed network connection") { | ||||||
|  | 				logger.LogNotice(fmt.Sprintln("[Client hung up]")) | ||||||
|  | 				return 0, io.EOF | ||||||
|  | 			} | ||||||
|  | 			etxt := fmt.Sprintf("** Failed read:%s (%s) **", "HMAC", err) | ||||||
|  | 			logger.LogErr(etxt) | ||||||
|  | 			return 0, errors.New(etxt) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		err = binary.Read(*hc.c, binary.BigEndian, &payloadLen) | 		err = binary.Read(*hc.c, binary.BigEndian, &payloadLen) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			if err.Error() != "EOF" { | 			if err.Error() == "EOF" { | ||||||
| 				logger.LogErr(fmt.Sprintln("[2]unexpected Read() err:", err)) | 				return 0, io.EOF | ||||||
| 			} | 			} | ||||||
|  | 			if strings.HasSuffix(err.Error(), "use of closed network connection") { | ||||||
|  | 				logger.LogNotice(fmt.Sprintln("[Client hung up]")) | ||||||
|  | 				return 0, io.EOF | ||||||
|  | 			} | ||||||
|  | 			etxt := fmt.Sprintf("** Failed read:%s (%s) **", "payloadLen", err) | ||||||
|  | 			logger.LogErr(etxt) | ||||||
|  | 			return 0, errors.New(etxt) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if payloadLen > MAX_PAYLOAD_LEN { | 		if payloadLen > MAX_PAYLOAD_LEN { | ||||||
|  | @ -733,15 +752,17 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 
 | 
 | ||||||
| 		var payloadBytes = make([]byte, payloadLen) | 		var payloadBytes = make([]byte, payloadLen) | ||||||
| 		n, err = io.ReadFull(*hc.c, payloadBytes) | 		n, err = io.ReadFull(*hc.c, payloadBytes) | ||||||
| 
 | 		if err != nil { | ||||||
| 		// Normal client 'exit' from interactive session will cause
 | 			if err.Error() == "EOF" { | ||||||
| 		// (on server side) err.Error() == "<iface/addr info ...>: use of closed network connection"
 | 				return 0, io.EOF | ||||||
| 		if err != nil && err.Error() != "EOF" { |  | ||||||
| 			if !strings.HasSuffix(err.Error(), "use of closed network connection") { |  | ||||||
| 				logger.LogErr(fmt.Sprintln("[3]unexpected Read() err:", err)) |  | ||||||
| 			} else { |  | ||||||
| 				logger.LogNotice(fmt.Sprintln("[Client hung up]")) |  | ||||||
| 			} | 			} | ||||||
|  | 			if strings.HasSuffix(err.Error(), "use of closed network connection") { | ||||||
|  | 				logger.LogNotice(fmt.Sprintln("[Client hung up]")) | ||||||
|  | 				return 0, io.EOF | ||||||
|  | 			} | ||||||
|  | 			etxt := fmt.Sprintf("** Failed read:%s (%s) **", "payloadBytes", err) | ||||||
|  | 			logger.LogErr(etxt) | ||||||
|  | 			return 0, errors.New(etxt) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		log.Printf("  <:ctext:\r\n%s\r\n", hex.Dump(payloadBytes[:n])) | 		log.Printf("  <:ctext:\r\n%s\r\n", hex.Dump(payloadBytes[:n])) | ||||||
|  | @ -797,19 +818,21 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 			} else if ctrlStatOp == CSOTunData { | 			} else if ctrlStatOp == CSOTunData { | ||||||
| 				lport := binary.BigEndian.Uint16(payloadBytes) | 				lport := binary.BigEndian.Uint16(payloadBytes) | ||||||
| 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | ||||||
| 				fmt.Printf("[Got CSOTunData: [lport %d:rport %d] data:%v\n", lport, rport, payloadBytes[4:]) | 				_ = lport | ||||||
|  | 				//fmt.Printf("[Got CSOTunData: [lport %d:rport %d] data:%v\n", lport, rport, payloadBytes[4:])
 | ||||||
| 				if hc.tuns[rport] == nil { | 				if hc.tuns[rport] == nil { | ||||||
| 					fmt.Printf("[Invalid rport:%d]\n", rport) | 					fmt.Printf("[Invalid rport:%d]\r\n", rport) | ||||||
| 				} else { | 				} else { | ||||||
| 					hc.tuns[rport] <- payloadBytes[4:] | 					hc.tuns[rport] <- payloadBytes[4:] | ||||||
| 				} | 				} | ||||||
| 				fmt.Printf("[Done stuffing hc.tuns[rport]\n") | 				//fmt.Printf("[Done stuffing hc.tuns[rport]\n")
 | ||||||
| 			} else if ctrlStatOp == CSOTunClose { | 			} else if ctrlStatOp == CSOTunClose { | ||||||
| 				lport := binary.BigEndian.Uint16(payloadBytes) | 				lport := binary.BigEndian.Uint16(payloadBytes) | ||||||
| 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | ||||||
| 				fmt.Printf("[Got CSOTunClose: [lport %d:rport %d]\n", lport, rport) | 				fmt.Printf("[Got CSOTunClose: [lport %d:rport %d]\r\n", lport, rport) | ||||||
| 				if hc.tuns[rport] != nil { | 				if hc.tuns[rport] != nil { | ||||||
| 					close(hc.tuns[rport]) | 					close(hc.tuns[rport]) | ||||||
|  | 					hc.tuns[rport] = nil | ||||||
| 				} | 				} | ||||||
| 			} else { | 			} else { | ||||||
| 				hc.dBuf.Write(payloadBytes) | 				hc.dBuf.Write(payloadBytes) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,228 @@ | ||||||
|  | // hkextun.go - Tunnel setup using an established hkexnet.Conn
 | ||||||
|  | 
 | ||||||
|  | // Copyright (c) 2017-2018 Russell Magee
 | ||||||
|  | // Licensed under the terms of the MIT license (see LICENSE.mit in this
 | ||||||
|  | // distribution)
 | ||||||
|  | //
 | ||||||
|  | // golang implementation by Russ Magee (rmagee_at_gmail.com)
 | ||||||
|  | 
 | ||||||
|  | package hkexnet | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"log" | ||||||
|  | 	"net" | ||||||
|  | 
 | ||||||
|  | 	"blitter.com/go/hkexsh/logger" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type ( | ||||||
|  | 	// Tunnels
 | ||||||
|  | 	// --
 | ||||||
|  | 	// 1. client is given (lport, remhost, rport) by local user
 | ||||||
|  | 	// 2. client sends [CSOTunReq:rport] to server
 | ||||||
|  | 	// client=> [CSOTunReq:rport] =>remhost
 | ||||||
|  | 	//
 | ||||||
|  | 	// remhost starts worker to receive/send data using rport
 | ||||||
|  | 	// remhost replies to client with rport to acknowledge tun is ready
 | ||||||
|  | 	// client<= [CSOTunAck:rport] <=remhost
 | ||||||
|  | 	//   ... or if rhost rport refuses connection, sends
 | ||||||
|  | 	//   [CSOTunRefused:rport]
 | ||||||
|  | 	//
 | ||||||
|  | 	// client starts worker to receive/send data using lport
 | ||||||
|  | 	// ... client disconnects: sends remhost [CSOTunClose:rport]
 | ||||||
|  | 	// ... or server disconnects: sends client [CSOTunClose:lport]
 | ||||||
|  | 	//     server at any time sends [CSOTunRefused:rport] if daemon died
 | ||||||
|  | 	// --
 | ||||||
|  | 
 | ||||||
|  | 	// TunEndpoint [securePort:peer:dataPort]
 | ||||||
|  | 	TunEndpoint struct { | ||||||
|  | 		Rport uint16 // Names are from client's perspective
 | ||||||
|  | 		Lport uint16 // ... ie., RPort is on server, LPort is on client
 | ||||||
|  | 		Peer  string //net.Addr
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	TunPacket struct { | ||||||
|  | 		n    uint32 | ||||||
|  | 		data []byte | ||||||
|  | 	} | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func startServerTunnel(hc *Conn, lport, rport uint16) { | ||||||
|  | 	if hc.tuns == nil { | ||||||
|  | 		hc.tuns = make(map[uint16]chan []byte) | ||||||
|  | 	} | ||||||
|  | 	if hc.tuns[rport] == nil { | ||||||
|  | 		hc.tuns[rport] = make(chan []byte, 32) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	addrs, _ := net.InterfaceAddrs() | ||||||
|  | 	t := TunEndpoint{Peer: addrs[0].String(), Lport: lport, Rport: rport} | ||||||
|  | 	var resp bytes.Buffer | ||||||
|  | 	binary.Write(&resp, binary.BigEndian, t.Lport) | ||||||
|  | 
 | ||||||
|  | 	//var dialHangup chan<- bool
 | ||||||
|  | 
 | ||||||
|  | 	c, err := net.Dial("tcp", fmt.Sprintf(":%d", rport)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.LogErr(fmt.Sprintf("Nothing is serving at rport :%d!", rport)) | ||||||
|  | 		binary.Write(&resp, binary.BigEndian, uint16(0)) | ||||||
|  | 		// Inform client of the tunPort
 | ||||||
|  | 		hc.WritePacket(resp.Bytes(), CSOTunRefused) | ||||||
|  | 	} else { | ||||||
|  | 		binary.Write(&resp, binary.BigEndian, t.Rport) | ||||||
|  | 		logger.LogNotice(fmt.Sprintf("[Tunnel Opened - %d:%s:%d]", t.Lport, t.Peer, t.Rport)) | ||||||
|  | 
 | ||||||
|  | 		//
 | ||||||
|  | 		// worker to read data from the rport (to encrypt & send to client)
 | ||||||
|  | 		//
 | ||||||
|  | 		go func() { | ||||||
|  | 			defer func() { | ||||||
|  | 				//if hc.tuns[rport] != nil {
 | ||||||
|  | 				//	close(hc.tuns[rport])
 | ||||||
|  | 				//	hc.tuns[rport] = nil
 | ||||||
|  | 				//}
 | ||||||
|  | 				c.Close() | ||||||
|  | 			}() | ||||||
|  | 
 | ||||||
|  | 			var tunDst bytes.Buffer | ||||||
|  | 			binary.Write(&tunDst, binary.BigEndian, t.Lport) | ||||||
|  | 			binary.Write(&tunDst, binary.BigEndian, t.Rport) | ||||||
|  | 			for { | ||||||
|  | 				rBuf := make([]byte, 1024) | ||||||
|  | 				// Read data from c, encrypt/write via hc to client(lport)
 | ||||||
|  | 				n, e := c.Read(rBuf) | ||||||
|  | 				if e != nil { | ||||||
|  | 					if e == io.EOF { | ||||||
|  | 						logger.LogNotice(fmt.Sprintf("rport Disconnected: shutting down tunnel %v\n", t)) | ||||||
|  | 					} else { | ||||||
|  | 						logger.LogErr(fmt.Sprintf("Read error from rport of tun %v\n%s", t, e)) | ||||||
|  | 					} | ||||||
|  | 					hc.WritePacket(resp.Bytes(), CSOTunClose) | ||||||
|  | 					fmt.Printf("Closing server rport net.Dial()\n") | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 				if n > 0 { | ||||||
|  | 					rBuf = append(tunDst.Bytes(), rBuf[:n]...) | ||||||
|  | 					logger.LogNotice(fmt.Sprintf("Got rport data:%v", tunDst.Bytes())) | ||||||
|  | 					hc.WritePacket(rBuf[:n+4], CSOTunData) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}() | ||||||
|  | 
 | ||||||
|  | 		// worker to read data from client (already decrypted) & fwd to rport
 | ||||||
|  | 		go func() { | ||||||
|  | 			defer func() { | ||||||
|  | 				//if hc.tuns[rport] != nil {
 | ||||||
|  | 					//close(hc.tuns[rport])
 | ||||||
|  | 					//hc.tuns[rport] = nil
 | ||||||
|  | 				//}
 | ||||||
|  | 				c.Close() | ||||||
|  | 			}() | ||||||
|  | 
 | ||||||
|  | 			for { | ||||||
|  | 				rData, ok := <-hc.tuns[rport] | ||||||
|  | 				if ok { | ||||||
|  | 					logger.LogNotice(fmt.Sprintf("Got client data:%v", rData)) | ||||||
|  | 					c.Write(rData) | ||||||
|  | 				} else { | ||||||
|  | 					logger.LogErr("!!! ERROR reading from hc.tuns[] channel !!!") | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}() | ||||||
|  | 
 | ||||||
|  | 		// Inform client of the tunPort
 | ||||||
|  | 		hc.WritePacket(resp.Bytes(), CSOTunAck) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func StartClientTunnel(hc *Conn, lport, rport uint16) { | ||||||
|  | 	go func() { | ||||||
|  | 		if hc.tuns == nil { | ||||||
|  | 			hc.tuns = make(map[uint16]chan []byte) | ||||||
|  | 		} | ||||||
|  | 		if hc.tuns[rport] == nil { | ||||||
|  | 			hc.tuns[rport] = make(chan []byte, 32) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		l, e := net.Listen("tcp", fmt.Sprintf(":%d", lport)) | ||||||
|  | 		if e != nil { | ||||||
|  | 			fmt.Printf("[Could not get lport %d! (%s)\n", lport, e) | ||||||
|  | 		} else { | ||||||
|  | 			defer l.Close() | ||||||
|  | 			for { | ||||||
|  | 				c, e := l.Accept() | ||||||
|  | 
 | ||||||
|  | 				defer func() { | ||||||
|  | 					//if hc.tuns[rport] != nil {
 | ||||||
|  | 					//	close(hc.tuns[rport])
 | ||||||
|  | 					//	hc.tuns[rport] = nil
 | ||||||
|  | 					//}
 | ||||||
|  | 					c.Close() | ||||||
|  | 				}() | ||||||
|  | 
 | ||||||
|  | 				if e != nil { | ||||||
|  | 					log.Printf("Accept() got error(%v), hanging up.\n", e) | ||||||
|  | 					break | ||||||
|  | 					//log.Fatal(err)
 | ||||||
|  | 				} else { | ||||||
|  | 					log.Println("Accepted client") | ||||||
|  | 
 | ||||||
|  | 					// outside client -> tunnel lport
 | ||||||
|  | 					go func() { | ||||||
|  | 						var tunDst bytes.Buffer | ||||||
|  | 						binary.Write(&tunDst, binary.BigEndian, lport) | ||||||
|  | 						binary.Write(&tunDst, binary.BigEndian, rport) | ||||||
|  | 						for { | ||||||
|  | 							rBuf := make([]byte, 1024) | ||||||
|  | 							//Read data from c, encrypt/write via hc to client(lport)
 | ||||||
|  | 							n, e := c.Read(rBuf) | ||||||
|  | 							if e != nil { | ||||||
|  | 								if e == io.EOF { | ||||||
|  | 									logger.LogNotice(fmt.Sprintf("lport Disconnected: shutting down tunnel [%d:%d]\n", lport, rport)) | ||||||
|  | 								} else { | ||||||
|  | 									logger.LogErr(fmt.Sprintf("Read error from lport of tun [%d:%d]\n%s", lport, rport, e)) | ||||||
|  | 								} | ||||||
|  | 								hc.WritePacket(tunDst.Bytes(), CSOTunClose) | ||||||
|  | 								break | ||||||
|  | 							} | ||||||
|  | 							if n > 0 { | ||||||
|  | 								rBuf = append(tunDst.Bytes(), rBuf[:n]...) | ||||||
|  | 								logger.LogNotice(fmt.Sprintf("Got lport data:%v\n", tunDst.Bytes())) | ||||||
|  | 								hc.WritePacket(rBuf[:n+4], CSOTunData) | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 					}() | ||||||
|  | 
 | ||||||
|  | 					// tunnel lport -> outside client (c)
 | ||||||
|  | 					go func() { | ||||||
|  | 						defer func() { | ||||||
|  | 							//if hc.tuns[rport] != nil {
 | ||||||
|  | 							//	close(hc.tuns[rport])
 | ||||||
|  | 							//	hc.tuns[rport] = nil
 | ||||||
|  | 							//}
 | ||||||
|  | 							c.Close() | ||||||
|  | 						}() | ||||||
|  | 
 | ||||||
|  | 						for { | ||||||
|  | 							//fmt.Printf("Reading from client hc.tuns[%d]\n", lport)
 | ||||||
|  | 							bytes, ok := <-hc.tuns[rport] | ||||||
|  | 							if ok { | ||||||
|  | 								//fmt.Printf("[Got this through tunnel:%v]\n", bytes)
 | ||||||
|  | 								c.Write(bytes) | ||||||
|  | 							} else { | ||||||
|  | 								fmt.Printf("[Channel closed? exiting client worker!]\n") | ||||||
|  | 								break | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 					}() | ||||||
|  | 
 | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  | } | ||||||
|  | @ -352,7 +352,7 @@ func requestTunnel(hc *hkexnet.Conn, lp uint16, p string /*net.Addr*/, rp uint16 | ||||||
| 	errL := binary.Read(hc, binary.BigEndian, &lportReply) | 	errL := binary.Read(hc, binary.BigEndian, &lportReply) | ||||||
| 	errR := binary.Read(hc, binary.BigEndian, &rportReply) | 	errR := binary.Read(hc, binary.BigEndian, &rportReply) | ||||||
| 	if errL == nil && errR == nil { | 	if errL == nil && errR == nil { | ||||||
| 		fmt.Printf("Server established tunnel [%d:%d]\n", lportReply, rportReply) | 		fmt.Printf("Server established tunnel [%d:%d]\r\n", lportReply, rportReply) | ||||||
| 		hkexnet.StartClientTunnel(hc, lp, rp) | 		hkexnet.StartClientTunnel(hc, lp, rp) | ||||||
| 	} else { | 	} else { | ||||||
| 		fmt.Println("FAILED reading remPort") | 		fmt.Println("FAILED reading remPort") | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue