| @@ -49,8 +49,20 @@ type tun struct { | |||||||
|  |  | ||||||
| type link struct { | type link struct { | ||||||
| 	transport.Socket | 	transport.Socket | ||||||
| 	id            string | 	// unique id of this link e.g uuid | ||||||
| 	loopback      bool | 	// which we define for ourselves | ||||||
|  | 	id string | ||||||
|  | 	// whether its a loopback connection | ||||||
|  | 	// this flag is used by the transport listener | ||||||
|  | 	// which accepts inbound quic connections | ||||||
|  | 	loopback bool | ||||||
|  | 	// whether its actually connected | ||||||
|  | 	// dialled side sets it to connected | ||||||
|  | 	// after sending the message. the | ||||||
|  | 	// listener waits for the connect | ||||||
|  | 	connected bool | ||||||
|  | 	// the last time we received a keepalive | ||||||
|  | 	// on this link from the remote side | ||||||
| 	lastKeepAlive time.Time | 	lastKeepAlive time.Time | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -173,7 +185,7 @@ func (t *tun) process() { | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// set message head | 			// set message head | ||||||
| 			newMsg.Header["Micro-Tunnel"] = "message" | 			newMsg.Header["Micro-Tunnel"] = msg.typ | ||||||
|  |  | ||||||
| 			// set the tunnel id on the outgoing message | 			// set the tunnel id on the outgoing message | ||||||
| 			newMsg.Header["Micro-Tunnel-Id"] = msg.id | 			newMsg.Header["Micro-Tunnel-Id"] = msg.id | ||||||
| @@ -186,13 +198,39 @@ func (t *tun) process() { | |||||||
|  |  | ||||||
| 			// send the message via the interface | 			// send the message via the interface | ||||||
| 			t.Lock() | 			t.Lock() | ||||||
|  |  | ||||||
| 			if len(t.links) == 0 { | 			if len(t.links) == 0 { | ||||||
| 				log.Debugf("No links to send to") | 				log.Debugf("No links to send to") | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			for node, link := range t.links { | 			for node, link := range t.links { | ||||||
|  | 				// if the link is not connected skip it | ||||||
|  | 				if !link.connected { | ||||||
|  | 					log.Debugf("Link for node %s not connected", node) | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				// if we're picking the link check the id | ||||||
|  | 				// this is where we explicitly set the link | ||||||
|  | 				// in a message received via the listen method | ||||||
|  | 				if len(msg.link) > 0 && link.id != msg.link { | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				// if the link was a loopback accepted connection | ||||||
|  | 				// and the message is being sent outbound via | ||||||
|  | 				// a dialled connection don't use this link | ||||||
| 				if link.loopback && msg.outbound { | 				if link.loopback && msg.outbound { | ||||||
| 					continue | 					continue | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
|  | 				// if the message was being returned by the loopback listener | ||||||
|  | 				// send it back up the loopback link only | ||||||
|  | 				if msg.loopback && !link.loopback { | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				// send the message via the current link | ||||||
| 				log.Debugf("Sending %+v to %s", newMsg, node) | 				log.Debugf("Sending %+v to %s", newMsg, node) | ||||||
| 				if err := link.Send(newMsg); err != nil { | 				if err := link.Send(newMsg); err != nil { | ||||||
| 					log.Debugf("Tunnel error sending %+v to %s: %v", newMsg, node, err) | 					log.Debugf("Tunnel error sending %+v to %s: %v", newMsg, node, err) | ||||||
| @@ -200,6 +238,7 @@ func (t *tun) process() { | |||||||
| 					continue | 					continue | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			t.Unlock() | 			t.Unlock() | ||||||
| 		case <-t.closed: | 		case <-t.closed: | ||||||
| 			return | 			return | ||||||
| @@ -209,15 +248,22 @@ func (t *tun) process() { | |||||||
|  |  | ||||||
| // process incoming messages | // process incoming messages | ||||||
| func (t *tun) listen(link *link) { | func (t *tun) listen(link *link) { | ||||||
|  | 	// remove the link on exit | ||||||
|  | 	defer func() { | ||||||
|  | 		log.Debugf("Tunnel deleting connection from %s", link.Remote()) | ||||||
|  | 		t.Lock() | ||||||
|  | 		delete(t.links, link.Remote()) | ||||||
|  | 		t.Unlock() | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	// let us know if its a loopback | ||||||
|  | 	var loopback bool | ||||||
|  |  | ||||||
| 	for { | 	for { | ||||||
| 		// process anything via the net interface | 		// process anything via the net interface | ||||||
| 		msg := new(transport.Message) | 		msg := new(transport.Message) | ||||||
| 		err := link.Recv(msg) | 		if err := link.Recv(msg); err != nil { | ||||||
| 		if err != nil { |  | ||||||
| 			log.Debugf("Tunnel link %s receive error: %#v", link.Remote(), err) | 			log.Debugf("Tunnel link %s receive error: %#v", link.Remote(), err) | ||||||
| 			t.Lock() |  | ||||||
| 			delete(t.links, link.Remote()) |  | ||||||
| 			t.Unlock() |  | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -232,21 +278,29 @@ func (t *tun) listen(link *link) { | |||||||
|  |  | ||||||
| 			// are we connecting to ourselves? | 			// are we connecting to ourselves? | ||||||
| 			if token == t.token { | 			if token == t.token { | ||||||
| 				t.Lock() |  | ||||||
| 				link.loopback = true | 				link.loopback = true | ||||||
| 				t.Unlock() | 				loopback = true | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | 			// set as connected | ||||||
|  | 			link.connected = true | ||||||
|  |  | ||||||
|  | 			// save the link once connected | ||||||
|  | 			t.Lock() | ||||||
|  | 			t.links[link.Remote()] = link | ||||||
|  | 			t.Unlock() | ||||||
|  |  | ||||||
| 			// nothing more to do | 			// nothing more to do | ||||||
| 			continue | 			continue | ||||||
| 		case "close": | 		case "close": | ||||||
| 			log.Debugf("Tunnel link %s closing connection", link.Remote()) | 			log.Debugf("Tunnel link %s closing connection", link.Remote()) | ||||||
| 			// TODO: handle the close message | 			// TODO: handle the close message | ||||||
| 			// maybe report io.EOF or kill the link | 			// maybe report io.EOF or kill the link | ||||||
| 			continue | 			return | ||||||
| 		case "keepalive": | 		case "keepalive": | ||||||
| 			log.Debugf("Tunnel link %s received keepalive", link.Remote()) | 			log.Debugf("Tunnel link %s received keepalive", link.Remote()) | ||||||
| 			t.Lock() | 			t.Lock() | ||||||
|  | 			// save the keepalive | ||||||
| 			link.lastKeepAlive = time.Now() | 			link.lastKeepAlive = time.Now() | ||||||
| 			t.Unlock() | 			t.Unlock() | ||||||
| 			continue | 			continue | ||||||
| @@ -258,6 +312,12 @@ func (t *tun) listen(link *link) { | |||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		// if its not connected throw away the link | ||||||
|  | 		if !link.connected { | ||||||
|  | 			log.Debugf("Tunnel link %s not connected", link.id) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		// strip message header | 		// strip message header | ||||||
| 		delete(msg.Header, "Micro-Tunnel") | 		delete(msg.Header, "Micro-Tunnel") | ||||||
|  |  | ||||||
| @@ -283,8 +343,10 @@ func (t *tun) listen(link *link) { | |||||||
| 		var s *socket | 		var s *socket | ||||||
| 		var exists bool | 		var exists bool | ||||||
|  |  | ||||||
|  | 		// If its a loopback connection then we've enabled link direction | ||||||
|  | 		// listening side is used for listening, the dialling side for dialling | ||||||
| 		switch { | 		switch { | ||||||
| 		case link.loopback: | 		case loopback: | ||||||
| 			s, exists = t.getSocket(id, "listener") | 			s, exists = t.getSocket(id, "listener") | ||||||
| 		default: | 		default: | ||||||
| 			// get the socket based on the tunnel id and session | 			// get the socket based on the tunnel id and session | ||||||
| @@ -298,6 +360,7 @@ func (t *tun) listen(link *link) { | |||||||
| 				s, exists = t.getSocket(id, "listener") | 				s, exists = t.getSocket(id, "listener") | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// bail if no socket has been found | 		// bail if no socket has been found | ||||||
| 		if !exists { | 		if !exists { | ||||||
| 			log.Debugf("Tunnel skipping no socket exists") | 			log.Debugf("Tunnel skipping no socket exists") | ||||||
| @@ -337,9 +400,11 @@ func (t *tun) listen(link *link) { | |||||||
|  |  | ||||||
| 		// construct the internal message | 		// construct the internal message | ||||||
| 		imsg := &message{ | 		imsg := &message{ | ||||||
| 			id:      id, | 			id:       id, | ||||||
| 			session: session, | 			session:  session, | ||||||
| 			data:    tmsg, | 			data:     tmsg, | ||||||
|  | 			link:     link.id, | ||||||
|  | 			loopback: loopback, | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// append to recv backlog | 		// append to recv backlog | ||||||
| @@ -399,13 +464,11 @@ func (t *tun) setupLink(node string) (*link, error) { | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// save the link | 	// create a new link | ||||||
| 	id := uuid.New().String() | 	link := newLink(c) | ||||||
| 	link := &link{ | 	link.connected = true | ||||||
| 		Socket: c, | 	// we made the outbound connection | ||||||
| 		id:     id, | 	// and sent the connect message | ||||||
| 	} |  | ||||||
| 	t.links[node] = link |  | ||||||
|  |  | ||||||
| 	// process incoming messages | 	// process incoming messages | ||||||
| 	go t.listen(link) | 	go t.listen(link) | ||||||
| @@ -430,30 +493,18 @@ func (t *tun) connect() error { | |||||||
| 		// accept inbound connections | 		// accept inbound connections | ||||||
| 		err := l.Accept(func(sock transport.Socket) { | 		err := l.Accept(func(sock transport.Socket) { | ||||||
| 			log.Debugf("Tunnel accepted connection from %s", sock.Remote()) | 			log.Debugf("Tunnel accepted connection from %s", sock.Remote()) | ||||||
| 			// save the link |  | ||||||
| 			id := uuid.New().String() |  | ||||||
| 			t.Lock() |  | ||||||
| 			link := &link{ |  | ||||||
| 				Socket: sock, |  | ||||||
| 				id:     id, |  | ||||||
| 			} |  | ||||||
| 			t.links[sock.Remote()] = link |  | ||||||
| 			t.Unlock() |  | ||||||
|  |  | ||||||
| 			// delete the link | 			// create a new link | ||||||
| 			defer func() { | 			link := newLink(sock) | ||||||
| 				log.Debugf("Tunnel deleting connection from %s", sock.Remote()) |  | ||||||
| 				t.Lock() |  | ||||||
| 				delete(t.links, sock.Remote()) |  | ||||||
| 				t.Unlock() |  | ||||||
| 			}() |  | ||||||
|  |  | ||||||
| 			// listen for inbound messages | 			// listen for inbound messages. | ||||||
|  | 			// only save the link once connected. | ||||||
|  | 			// we do this inside liste | ||||||
| 			t.listen(link) | 			t.listen(link) | ||||||
| 		}) | 		}) | ||||||
|  |  | ||||||
| 		t.Lock() | 		t.RLock() | ||||||
| 		defer t.Unlock() | 		defer t.RUnlock() | ||||||
|  |  | ||||||
| 		// still connected but the tunnel died | 		// still connected but the tunnel died | ||||||
| 		if err != nil && t.connected { | 		if err != nil && t.connected { | ||||||
| @@ -473,6 +524,7 @@ func (t *tun) connect() error { | |||||||
| 			log.Debugf("Tunnel failed to establish node link to %s: %v", node, err) | 			log.Debugf("Tunnel failed to establish node link to %s: %v", node, err) | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// save the link | 		// save the link | ||||||
| 		t.links[node] = link | 		t.links[node] = link | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								tunnel/link.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								tunnel/link.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | package tunnel | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"github.com/google/uuid" | ||||||
|  | 	"github.com/micro/go-micro/transport" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func newLink(s transport.Socket) *link { | ||||||
|  | 	return &link{ | ||||||
|  | 		Socket: s, | ||||||
|  | 		id:     uuid.New().String(), | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -41,6 +41,10 @@ func (t *tunListener) process() { | |||||||
| 					id: m.id, | 					id: m.id, | ||||||
| 					// the session id | 					// the session id | ||||||
| 					session: m.session, | 					session: m.session, | ||||||
|  | 					// is loopback conn | ||||||
|  | 					loopback: m.loopback, | ||||||
|  | 					// the link the message was received on | ||||||
|  | 					link: m.link, | ||||||
| 					// close chan | 					// close chan | ||||||
| 					closed: make(chan bool), | 					closed: make(chan bool), | ||||||
| 					// recv called by the acceptor | 					// recv called by the acceptor | ||||||
|   | |||||||
| @@ -25,18 +25,28 @@ type socket struct { | |||||||
| 	recv chan *message | 	recv chan *message | ||||||
| 	// wait until we have a connection | 	// wait until we have a connection | ||||||
| 	wait chan bool | 	wait chan bool | ||||||
| 	// outbound marks the socket as outbound | 	// outbound marks the socket as outbound dialled connection | ||||||
| 	outbound bool | 	outbound bool | ||||||
|  | 	// lookback marks the socket as a loopback on the inbound | ||||||
|  | 	loopback bool | ||||||
|  | 	// the link on which this message was received | ||||||
|  | 	link string | ||||||
| } | } | ||||||
|  |  | ||||||
| // message is sent over the send channel | // message is sent over the send channel | ||||||
| type message struct { | type message struct { | ||||||
|  | 	// type of message | ||||||
|  | 	typ string | ||||||
| 	// tunnel id | 	// tunnel id | ||||||
| 	id string | 	id string | ||||||
| 	// the session id | 	// the session id | ||||||
| 	session string | 	session string | ||||||
| 	// outbound marks the message as outbound | 	// outbound marks the message as outbound | ||||||
| 	outbound bool | 	outbound bool | ||||||
|  | 	// loopback marks the message intended for loopback | ||||||
|  | 	loopback bool | ||||||
|  | 	// the link to send the message on | ||||||
|  | 	link string | ||||||
| 	// transport data | 	// transport data | ||||||
| 	data *transport.Message | 	data *transport.Message | ||||||
| } | } | ||||||
| @@ -77,10 +87,15 @@ func (s *socket) Send(m *transport.Message) error { | |||||||
|  |  | ||||||
| 	// append to backlog | 	// append to backlog | ||||||
| 	msg := &message{ | 	msg := &message{ | ||||||
|  | 		typ:      "message", | ||||||
| 		id:       s.id, | 		id:       s.id, | ||||||
| 		session:  s.session, | 		session:  s.session, | ||||||
| 		outbound: s.outbound, | 		outbound: s.outbound, | ||||||
|  | 		loopback: s.loopback, | ||||||
| 		data:     data, | 		data:     data, | ||||||
|  | 		// specify the link on which to send this | ||||||
|  | 		// it will be blank for dialled sockets | ||||||
|  | 		link: s.link, | ||||||
| 	} | 	} | ||||||
| 	log.Debugf("Appending %+v to send backlog", msg) | 	log.Debugf("Appending %+v to send backlog", msg) | ||||||
| 	s.send <- msg | 	s.send <- msg | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user