145 lines
3.7 KiB
Go
145 lines
3.7 KiB
Go
// Licensed to Elasticsearch B.V. under one or more contributor
|
|
// license agreements. See the NOTICE file distributed with
|
|
// this work for additional information regarding copyright
|
|
// ownership. Elasticsearch B.V. licenses this file to you under
|
|
// the Apache License, Version 2.0 (the "License"); you may
|
|
// not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
package socket
|
|
|
|
import (
|
|
"net"
|
|
)
|
|
|
|
// Direction indicates how a socket was initiated.
|
|
type Direction uint8
|
|
|
|
const (
|
|
_ Direction = iota
|
|
// Incoming indicates a connection was established from the outside to
|
|
// listening socket on this host.
|
|
Incoming
|
|
// Outgoing indicates a connection was established from this socket to an
|
|
// external listening socket.
|
|
Outgoing
|
|
// Listening indicates a socket that is listening.
|
|
Listening
|
|
)
|
|
|
|
var directionNames = map[Direction]string{
|
|
Incoming: "incoming",
|
|
Outgoing: "outgoing",
|
|
Listening: "listening",
|
|
}
|
|
|
|
func (d Direction) String() string {
|
|
if name, exists := directionNames[d]; exists {
|
|
return name
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
// ipList is a list of IP addresses.
|
|
type ipList struct {
|
|
ips []net.IP
|
|
}
|
|
|
|
func (l *ipList) put(ip net.IP) { l.ips = append(l.ips, ip) }
|
|
|
|
// portTable is a mapping of port number to listening IP addresses.
|
|
type portTable map[int]*ipList
|
|
|
|
// protocolTable is a mapping of protocol numbers to listening ports.
|
|
type protocolTable map[uint8]portTable
|
|
|
|
// ListenerTable tracks sockets that are listening. It can then be used to
|
|
// identify if a socket is listening, incoming, or outgoing.
|
|
type ListenerTable struct {
|
|
data protocolTable
|
|
}
|
|
|
|
// NewListenerTable returns a new ListenerTable.
|
|
func NewListenerTable() *ListenerTable {
|
|
return &ListenerTable{
|
|
data: protocolTable{},
|
|
}
|
|
}
|
|
|
|
// Reset resets all data in the table.
|
|
func (t *ListenerTable) Reset() {
|
|
for _, ports := range t.data {
|
|
for port := range ports {
|
|
delete(ports, port)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Put puts a new listening address into the table.
|
|
func (t *ListenerTable) Put(proto uint8, ip net.IP, port int) {
|
|
ports, exists := t.data[proto]
|
|
if !exists {
|
|
ports = portTable{}
|
|
t.data[proto] = ports
|
|
}
|
|
|
|
// Add port + addr to table.
|
|
interfaces, exists := ports[port]
|
|
if !exists {
|
|
interfaces = &ipList{}
|
|
ports[port] = interfaces
|
|
}
|
|
interfaces.put(ip)
|
|
}
|
|
|
|
// Direction returns whether the connection was incoming or outgoing based on
|
|
// the protocol and local address. It compares the given local address to the
|
|
// listeners in the table for the protocol and returns Incoming if there is a
|
|
// match. If remotePort is 0 then Listening is returned.
|
|
func (t *ListenerTable) Direction(
|
|
proto uint8,
|
|
localIP net.IP, localPort int,
|
|
remoteIP net.IP, remotePort int,
|
|
) Direction {
|
|
if remotePort == 0 {
|
|
return Listening
|
|
}
|
|
|
|
// Are there any listeners on the given protocol?
|
|
ports, exists := t.data[proto]
|
|
if !exists {
|
|
return Outgoing
|
|
}
|
|
|
|
// Is there any listener on the port?
|
|
interfaces, exists := ports[localPort]
|
|
if !exists {
|
|
return Outgoing
|
|
}
|
|
|
|
// Is there a listener that specific interface? OR
|
|
// Is there a listener on the "any" address (0.0.0.0 or ::)?
|
|
isIPv4 := localIP.To4() != nil
|
|
for _, ip := range interfaces.ips {
|
|
switch {
|
|
case ip.Equal(localIP):
|
|
return Incoming
|
|
case ip.Equal(net.IPv4zero) && isIPv4:
|
|
return Incoming
|
|
case ip.Equal(net.IPv6zero) && !isIPv4:
|
|
return Incoming
|
|
}
|
|
}
|
|
|
|
return Outgoing
|
|
}
|