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
|
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed 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.
// +build dragonfly freebsd netbsd
package server
import (
"fmt"
"net"
"os"
"syscall"
log "github.com/sirupsen/logrus"
)
const (
TCP_MD5SIG = 0x10 // TCP MD5 Signature (RFC2385)
IPV6_MINHOPCOUNT = 73 // Generalized TTL Security Mechanism (RFC5082)
)
func setsockoptTcpMD5Sig(fd int, address string, key string) error {
// always enable and assumes that the configuration is done by setkey()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, TCP_MD5SIG, 1))
}
func SetTcpMD5SigSockopt(l *net.TCPListener, address string, key string) error {
fi, _, err := extractFileAndFamilyFromTCPListener(l)
defer fi.Close()
if err != nil {
return err
}
return setsockoptTcpMD5Sig(int(fi.Fd()), address, key)
}
func setsockoptIpTtl(fd int, family int, value int) error {
level := syscall.IPPROTO_IP
name := syscall.IP_TTL
if family == syscall.AF_INET6 {
level = syscall.IPPROTO_IPV6
name = syscall.IPV6_UNICAST_HOPS
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, level, name, value))
}
func SetListenTcpTTLSockopt(l *net.TCPListener, ttl int) error {
fi, family, err := extractFileAndFamilyFromTCPListener(l)
defer fi.Close()
if err != nil {
return err
}
return setsockoptIpTtl(int(fi.Fd()), family, ttl)
}
func SetTcpTTLSockopt(conn *net.TCPConn, ttl int) error {
fi, family, err := extractFileAndFamilyFromTCPConn(conn)
defer fi.Close()
if err != nil {
return err
}
return setsockoptIpTtl(int(fi.Fd()), family, ttl)
}
func setsockoptIpMinTtl(fd int, family int, value int) error {
level := syscall.IPPROTO_IP
name := syscall.IP_MINTTL
if family == syscall.AF_INET6 {
level = syscall.IPPROTO_IPV6
name = IPV6_MINHOPCOUNT
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, level, name, value))
}
func SetTcpMinTTLSockopt(conn *net.TCPConn, ttl int) error {
fi, family, err := extractFileAndFamilyFromTCPConn(conn)
defer fi.Close()
if err != nil {
return err
}
return setsockoptIpMinTtl(int(fi.Fd()), family, ttl)
}
type TCPDialer struct {
net.Dialer
// MD5 authentication password.
AuthPassword string
// The TTL value to set outgoing connection.
Ttl uint8
// The minimum TTL value for incoming packets.
TtlMin uint8
}
func (d *TCPDialer) DialTCP(addr string, port int) (*net.TCPConn, error) {
if d.AuthPassword != "" {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": addr,
}).Warn("setting md5 for active connection is not supported")
}
if d.Ttl != 0 {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": addr,
}).Warn("setting ttl for active connection is not supported")
}
if d.TtlMin != 0 {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": addr,
}).Warn("setting min ttl for active connection is not supported")
}
raddr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(addr, fmt.Sprintf("%d", port)))
if err != nil {
return nil, fmt.Errorf("invalid remote address: %s", err)
}
laddr, err := net.ResolveTCPAddr("tcp", d.LocalAddr.String())
if err != nil {
return nil, fmt.Errorf("invalid local address: %s", err)
}
dialer := net.Dialer{LocalAddr: laddr, Timeout: d.Timeout}
conn, err := dialer.Dial("tcp", raddr.String())
if err != nil {
return nil, err
}
return conn.(*net.TCPConn), nil
}
|