mirror of
https://github.com/balzack/databag.git
synced 2025-02-11 19:19:16 +00:00
removing sturn implementation
This commit is contained in:
parent
55e4bef78e
commit
3efe2f75ab
@ -1,256 +0,0 @@
|
||||
package sturn
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"errors"
|
||||
"strings"
|
||||
"strconv"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func readAttribute(buf []byte, pos int) (error, *SturnAttribute, int) {
|
||||
|
||||
if len(buf) - pos < 4 {
|
||||
return errors.New("invalid attribute length"), nil, 0
|
||||
}
|
||||
atrType := getAttributeType(buf[pos + 0], buf[pos + 1])
|
||||
atrLength := int(buf[pos + 2]) * 256 + int(buf[pos + 3])
|
||||
padLength := ((atrLength + 3) >> 2) << 2
|
||||
if len(buf) - pos < 4 + padLength {
|
||||
return errors.New("invalid attribute buffer"), nil, 0
|
||||
}
|
||||
|
||||
attr := &SturnAttribute{ atrType: atrType }
|
||||
if atrType == ATRRequestedTransport {
|
||||
if buf[pos + 5] != 0x00 || buf[pos + 6] != 0x00 || buf[pos + 7] != 0x00 {
|
||||
return errors.New("invalid attribute"), nil, 0
|
||||
}
|
||||
attr.intValue = int32(buf[pos + 4])
|
||||
} else if atrType == ATRLifetime {
|
||||
attr.intValue = 256 * (256 * (256 * int32(buf[pos + 4]) + int32(buf[pos + 5])) + int32(buf[pos + 6])) + int32(buf[pos + 7]);
|
||||
} else if atrType == ATRNonce {
|
||||
attr.strValue = string(buf[pos + 4:pos + 4+atrLength]);
|
||||
} else if atrType == ATRUsername {
|
||||
attr.strValue = string(buf[pos + 4:pos + 4+atrLength]);
|
||||
} else if atrType == ATRRealm {
|
||||
attr.strValue = string(buf[pos + 4:pos + 4+atrLength]);
|
||||
} else if atrType == ATRMessageIntegrity {
|
||||
//fmt.Println("HANDLE: ATRMessageIntegrity");
|
||||
} else if atrType == ATRMessageIntegritySha256 {
|
||||
//fmt.Println("HANDLE: ATRMessageIntegritySha256");
|
||||
} else if atrType == ATRFingerprint {
|
||||
//fmt.Println("HANDLE: ATRFingerprint");
|
||||
} else if atrType == ATRXorPeerAddress {
|
||||
if padLength != 8 {
|
||||
return errors.New("invalid attribute size"), nil, 0
|
||||
}
|
||||
if buf[pos + 4] != 0 || buf[pos + 5] != FAMIPv4 {
|
||||
return errors.New("unsupported protocol family"), nil, 0
|
||||
}
|
||||
attr.strValue = ""
|
||||
attr.strValue += strconv.Itoa(int(buf[pos + 8] ^ 0x21))
|
||||
attr.strValue += "."
|
||||
attr.strValue += strconv.Itoa(int(buf[pos + 9] ^ 0x12))
|
||||
attr.strValue += "."
|
||||
attr.strValue += strconv.Itoa(int(buf[pos + 10] ^ 0xA4))
|
||||
attr.strValue += "."
|
||||
attr.strValue += strconv.Itoa(int(buf[pos + 11] ^ 0x42))
|
||||
attr.intValue = int32(buf[pos + 6] ^ 0x21)
|
||||
attr.intValue *= 256
|
||||
attr.intValue += int32(buf[pos + 7] ^ 0x12)
|
||||
} else if atrType == ATRData {
|
||||
for i := 0; i < atrLength; i++ {
|
||||
attr.binValue = append(attr.binValue, buf[pos + 4 + i])
|
||||
}
|
||||
} else {
|
||||
fmt.Println("UNKNOWN ATTRIBUTE", atrType);
|
||||
}
|
||||
|
||||
return nil, attr, 4 + padLength
|
||||
}
|
||||
|
||||
func writeAttribute(attribute *SturnAttribute, buf []byte, pos int) (error, int) {
|
||||
|
||||
if len(buf) - pos < 4 {
|
||||
return errors.New("invalid buffer size"), 0
|
||||
}
|
||||
|
||||
if attribute.atrType == ATRXorMappedAddress {
|
||||
if len(buf) - pos < 12 {
|
||||
return errors.New("invalid buffer size"), 0
|
||||
}
|
||||
ip := 0
|
||||
parts := strings.Split(attribute.strValue, ".");
|
||||
for i := 0; i < 4; i++ {
|
||||
val, _ := strconv.Atoi(parts[i]);
|
||||
ip = (ip * 256) + val;
|
||||
}
|
||||
buf[pos + 1], buf[pos + 0] = setAttributeType(ATRXorMappedAddress);
|
||||
buf[pos + 2] = 0x00
|
||||
buf[pos + 3] = 0x08
|
||||
buf[pos + 4] = 0x00
|
||||
buf[pos + 5] = FAMIPv4
|
||||
buf[pos + 6] = byte((attribute.intValue >> 8) % 256) ^ 0x21
|
||||
buf[pos + 7] = byte((attribute.intValue) % 256) ^ 0x12
|
||||
buf[pos + 8] = byte((ip >> 24) % 256) ^ 0x21
|
||||
buf[pos + 9] = byte((ip >> 16) % 256) ^ 0x12
|
||||
buf[pos + 10] = byte((ip >> 8) % 256) ^ 0xA4
|
||||
buf[pos + 11] = byte(ip % 256) ^ 0x42
|
||||
return nil, 12
|
||||
} else if attribute.atrType == ATRXorRelayedAddress {
|
||||
if len(buf) - pos < 12 {
|
||||
return errors.New("invalid buffer size"), 0
|
||||
}
|
||||
ip := 0
|
||||
parts := strings.Split(attribute.strValue, ".");
|
||||
for i := 0; i < 4; i++ {
|
||||
val, _ := strconv.Atoi(parts[i]);
|
||||
ip = (ip * 256) + val;
|
||||
}
|
||||
buf[pos + 1], buf[pos + 0] = setAttributeType(ATRXorRelayedAddress);
|
||||
buf[pos + 2] = 0x00
|
||||
buf[pos + 3] = 0x08
|
||||
buf[pos + 4] = 0x00
|
||||
buf[pos + 5] = FAMIPv4
|
||||
buf[pos + 6] = byte((attribute.intValue >> 8) % 256) ^ 0x21
|
||||
buf[pos + 7] = byte(attribute.intValue % 256) ^ 0x12
|
||||
buf[pos + 8] = byte((ip >> 24) % 256) ^ 0x21
|
||||
buf[pos + 9] = byte((ip >> 16) % 256) ^ 0x12
|
||||
buf[pos + 10] = byte((ip >> 8) % 256) ^ 0xA4
|
||||
buf[pos + 11] = byte(ip % 256) ^ 0x42
|
||||
return nil, 12
|
||||
} else if attribute.atrType == ATRXorPeerAddress {
|
||||
if len(buf) - pos < 12 {
|
||||
return errors.New("invalid buffer size"), 0
|
||||
}
|
||||
ip := 0
|
||||
parts := strings.Split(attribute.strValue, ".");
|
||||
for i := 0; i < 4; i++ {
|
||||
val, _ := strconv.Atoi(parts[i]);
|
||||
ip = (ip * 256) + val;
|
||||
}
|
||||
buf[pos + 1], buf[pos + 0] = setAttributeType(ATRXorPeerAddress);
|
||||
buf[pos + 2] = 0x00
|
||||
buf[pos + 3] = 0x08
|
||||
buf[pos + 4] = 0x00
|
||||
buf[pos + 5] = FAMIPv4
|
||||
buf[pos + 6] = byte((attribute.intValue >> 8) % 256) ^ 0x21
|
||||
buf[pos + 7] = byte(attribute.intValue % 256) ^ 0x12
|
||||
buf[pos + 8] = byte((ip >> 24) % 256) ^ 0x21
|
||||
buf[pos + 9] = byte((ip >> 16) % 256) ^ 0x12
|
||||
buf[pos + 10] = byte((ip >> 8) % 256) ^ 0xA4
|
||||
buf[pos + 11] = byte(ip % 256) ^ 0x42
|
||||
return nil, 12
|
||||
} else if attribute.atrType == ATRData {
|
||||
paddedLen := ((len(attribute.binValue) + 3) >> 2) << 2
|
||||
if len(buf) - pos < 4 + paddedLen {
|
||||
return errors.New("invalid buffer size"), 0
|
||||
}
|
||||
buf[pos + 1], buf[pos + 0] = setAttributeType(ATRData)
|
||||
buf[pos + 2] = byte((len(attribute.binValue) >> 8) % 256)
|
||||
buf[pos + 3] = byte(len(attribute.binValue) % 256)
|
||||
for i := 0; i < len(attribute.binValue); i++ {
|
||||
buf[pos + 4 + i] = attribute.binValue[i]
|
||||
}
|
||||
for i := len(attribute.binValue); i < paddedLen; i++ {
|
||||
buf[pos + 4 + i] = 0x00
|
||||
}
|
||||
return nil, 4 + paddedLen
|
||||
} else if attribute.atrType == ATRLifetime {
|
||||
if len(buf) - pos < 8 {
|
||||
return errors.New("invalid buffer size"), 0
|
||||
}
|
||||
buf[pos + 1], buf[pos + 0] = setAttributeType(ATRLifetime);
|
||||
buf[pos + 2] = 0x00
|
||||
buf[pos + 3] = 0x04
|
||||
buf[pos + 4] = byte((attribute.intValue >> 24) % 256);
|
||||
buf[pos + 5] = byte((attribute.intValue >> 16) % 256);
|
||||
buf[pos + 6] = byte((attribute.intValue >> 8) % 256);
|
||||
buf[pos + 7] = byte(attribute.intValue % 256);
|
||||
return nil, 8
|
||||
} else if attribute.atrType == ATRNonce {
|
||||
raw := []byte(attribute.strValue)
|
||||
rawLen := len(raw);
|
||||
paddedLen := ((len(raw) + 3) >> 2) << 2
|
||||
if paddedLen >= 256 {
|
||||
return errors.New("invalid attribute size"), 0
|
||||
}
|
||||
if len(buf) - pos < 4 + paddedLen {
|
||||
return errors.New("invalid buffer size"), 0
|
||||
}
|
||||
buf[pos + 1], buf[pos + 0] = setAttributeType(ATRNonce);
|
||||
buf[pos + 2] = 0x00
|
||||
buf[pos + 3] = byte(rawLen)
|
||||
for i := 0; i < len(raw); i++ {
|
||||
buf[pos + 4 + i] = raw[i];
|
||||
}
|
||||
for i := len(raw); i < paddedLen; i++ {
|
||||
buf[pos + 4 + i] = 0x00;
|
||||
}
|
||||
return nil, 4 + paddedLen
|
||||
} else if attribute.atrType == ATRRealm {
|
||||
raw := []byte(attribute.strValue)
|
||||
rawLen := len(raw);
|
||||
paddedLen := ((len(raw) + 3) >> 2) << 2
|
||||
if paddedLen >= 256 {
|
||||
return errors.New("invalid attribute size"), 0
|
||||
}
|
||||
if len(buf) - pos < 4 + paddedLen {
|
||||
return errors.New("invalid buffer size"), 0
|
||||
}
|
||||
buf[pos + 1], buf[pos + 0] = setAttributeType(ATRRealm);
|
||||
buf[pos + 2] = 0x00
|
||||
buf[pos + 3] = byte(rawLen);
|
||||
for i := 0; i < len(raw); i++ {
|
||||
buf[pos + 4 + i] = raw[i];
|
||||
}
|
||||
for i := len(raw); i < paddedLen; i++ {
|
||||
buf[pos + 4 + i] = 0x00;
|
||||
}
|
||||
return nil, 4 + paddedLen
|
||||
} else if attribute.atrType == ATRErrorCode {
|
||||
if len(buf) - pos < 8 {
|
||||
return errors.New("invalid buffer size"), 0
|
||||
}
|
||||
buf[pos + 1], buf[pos + 0] = setAttributeType(ATRErrorCode);
|
||||
buf[pos + 2] = 0x00
|
||||
buf[pos + 3] = 0x04
|
||||
buf[pos + 4] = 0x00
|
||||
buf[pos + 5] = 0x00
|
||||
buf[pos + 6] = byte(attribute.intValue / 100)
|
||||
buf[pos + 7] = byte(attribute.intValue % 100)
|
||||
return nil, 8
|
||||
} else if attribute.atrType == ATRMessageIntegrity {
|
||||
buf[pos + 1], buf[pos + 0] = setAttributeType(ATRMessageIntegrity);
|
||||
buf[pos + 2] = 0;
|
||||
buf[pos + 3] = 0x14;
|
||||
key := md5.Sum([]byte("user:databag.dweb:pass"));
|
||||
|
||||
// set hash size
|
||||
lengthField0 := buf[2]
|
||||
lengthField1 := buf[3]
|
||||
hashLength := pos + 4
|
||||
buf[2] = byte((hashLength >> 8) % 256);
|
||||
buf[3] = byte(hashLength % 256);
|
||||
hash := getHmac(key[:], buf[0:pos]);
|
||||
buf[2] = lengthField0
|
||||
buf[3] = lengthField1
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
buf[4 + pos + i] = hash[i];
|
||||
}
|
||||
|
||||
return nil, 24
|
||||
} else {
|
||||
fmt.Println("UNKNOWN!");
|
||||
}
|
||||
return nil, 8
|
||||
}
|
||||
|
||||
func getHmac(key []byte, data []byte) []byte {
|
||||
mac := hmac.New(sha1.New, key)
|
||||
mac.Write(data)
|
||||
return mac.Sum(nil)
|
||||
}
|
@ -1,480 +0,0 @@
|
||||
package sturn
|
||||
|
||||
import (
|
||||
"net"
|
||||
"fmt"
|
||||
"errors"
|
||||
"bytes"
|
||||
"strings"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func readMessage(buf []byte) (error, *SturnMessage) {
|
||||
if len(buf) < 20 {
|
||||
return errors.New("invalid header size"), nil
|
||||
}
|
||||
if buf[0] & 0xC0 != 0 {
|
||||
return errors.New("invalid message prefix"), nil
|
||||
}
|
||||
magic := []byte{0x21, 0x12, 0xA4, 0x42 }
|
||||
if !bytes.Equal(magic, buf[4:8]) {
|
||||
return errors.New("invalid message cookie"), nil
|
||||
}
|
||||
atrLength := int(buf[2]) * 256 + int(buf[3])
|
||||
if atrLength + 20 != len(buf) {
|
||||
return errors.New("invalid message length"), nil
|
||||
}
|
||||
|
||||
class, method := getMessageType(buf[0], buf[1]);
|
||||
transaction := buf[8:20];
|
||||
|
||||
var attributes []SturnAttribute
|
||||
var pos int = 0
|
||||
for pos < atrLength {
|
||||
err, attr, n := readAttribute(buf, pos + 20)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
pos += n
|
||||
attributes = append(attributes, *attr);
|
||||
}
|
||||
|
||||
return nil, &SturnMessage{
|
||||
class: class,
|
||||
method: method,
|
||||
transaction: transaction,
|
||||
attributes: attributes,
|
||||
}
|
||||
}
|
||||
|
||||
func writeMessage(msg *SturnMessage, buf []byte) (error, int) {
|
||||
if len(buf) < 20 {
|
||||
return errors.New("invalid buffer length"), 0
|
||||
}
|
||||
|
||||
// set prefix
|
||||
buf[0], buf[1] = setMessageType(msg.class, msg.method)
|
||||
|
||||
// init size
|
||||
buf[2] = 0x00
|
||||
buf[3] = 0x00
|
||||
|
||||
// set cookie
|
||||
buf[4] = 0x21
|
||||
buf[5] = 0x12
|
||||
buf[6] = 0xA4
|
||||
buf[7] = 0x42
|
||||
|
||||
// set transaction
|
||||
for i := 0; i < 12; i++ {
|
||||
buf[8 + i] = msg.transaction[i];
|
||||
}
|
||||
|
||||
// set each attribute
|
||||
pos := 0
|
||||
for _, attribute := range msg.attributes {
|
||||
err, n := writeAttribute(&attribute, buf, 20 + pos);
|
||||
if err != nil {
|
||||
return err, 0
|
||||
}
|
||||
pos += n;
|
||||
|
||||
// set size
|
||||
buf[2] = byte((pos >> 8) % 256);
|
||||
buf[3] = byte(pos % 256);
|
||||
}
|
||||
|
||||
return nil, pos + 20;
|
||||
}
|
||||
|
||||
func (s *Sturn) handleMessage(buf []byte, addr net.Addr) {
|
||||
|
||||
err, msg := readMessage(buf);
|
||||
if err != nil {
|
||||
fmt.Println(err, addr.String(), buf);
|
||||
return
|
||||
}
|
||||
if msg == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if msg.class == CLSRequest && msg.method == MEHBinding {
|
||||
fmt.Println("stun/turn binding request");
|
||||
s.handleBindingRequest(msg, addr);
|
||||
} else if msg.class == CLSRequest && msg.method == MEHAllocate {
|
||||
fmt.Println("stun/turn allocate request");
|
||||
s.handleAllocateRequest(msg, addr);
|
||||
} else if msg.class == CLSRequest && msg.method == MEHRefresh {
|
||||
fmt.Println("stun/turn refresh request");
|
||||
s.handleRefreshRequest(msg, addr);
|
||||
} else if msg.class == CLSRequest && msg.method == MEHCreatePermission {
|
||||
fmt.Println("stun/turn create permission request");
|
||||
s.handleCreatePermissionRequest(msg, addr);
|
||||
} else if msg.class == CLSIndication && msg.method == MEHSend {
|
||||
fmt.Println("stun/turn send");
|
||||
s.handleSendIndication(msg, addr, buf);
|
||||
} else {
|
||||
fmt.Println("unsupported message", buf);
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Sturn) sendRequestError(msg *SturnMessage, addr net.Addr, code int32) {
|
||||
var attributes []SturnAttribute
|
||||
attributes = append(attributes, SturnAttribute{
|
||||
atrType: ATRErrorCode,
|
||||
intValue: code,
|
||||
})
|
||||
attributes = append(attributes, SturnAttribute{
|
||||
atrType: ATRNonce,
|
||||
strValue: "",
|
||||
})
|
||||
attributes = append(attributes, SturnAttribute{
|
||||
atrType: ATRRealm,
|
||||
strValue: "databag.dweb",
|
||||
})
|
||||
response := &SturnMessage{
|
||||
class: CLSError,
|
||||
method: msg.method,
|
||||
transaction: msg.transaction,
|
||||
attributes: attributes,
|
||||
};
|
||||
err, n := writeMessage(response, s.buf);
|
||||
if err != nil {
|
||||
fmt.Printf("failed to write stun response");
|
||||
} else {
|
||||
(*s.conn).WriteTo(s.buf[:n], addr);
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Sturn) handleCreatePermissionRequest(msg *SturnMessage, addr net.Addr) {
|
||||
|
||||
username := getAttribute(msg, ATRUsername)
|
||||
if username == nil {
|
||||
fmt.Println("no username", addr.String(), msg.transaction);
|
||||
s.sendRequestError(msg, addr, 401)
|
||||
return
|
||||
}
|
||||
permission := getAttribute(msg, ATRXorPeerAddress)
|
||||
if permission == nil {
|
||||
fmt.Println("no peer");
|
||||
s.sendRequestError(msg, addr, 400)
|
||||
return
|
||||
}
|
||||
|
||||
s.sync.Lock();
|
||||
defer s.sync.Unlock();
|
||||
_, set := sturn.sessions[username.strValue]
|
||||
if !set {
|
||||
fmt.Println("no session", addr.String());
|
||||
s.sendRequestError(msg, addr, 401)
|
||||
return
|
||||
}
|
||||
|
||||
source := addr.String()
|
||||
allocation, found := s.allocations[source]
|
||||
if !found {
|
||||
fmt.Println("no allocation");
|
||||
s.sendRequestError(msg, addr, 400)
|
||||
return
|
||||
}
|
||||
|
||||
allocation.permissions = append(allocation.permissions, permission.strValue);
|
||||
|
||||
var attributes []SturnAttribute
|
||||
attributes = append(attributes, SturnAttribute{
|
||||
atrType: ATRMessageIntegrity,
|
||||
});
|
||||
|
||||
response := &SturnMessage{
|
||||
class: CLSResponse,
|
||||
method: MEHCreatePermission,
|
||||
transaction: msg.transaction,
|
||||
attributes: attributes,
|
||||
};
|
||||
err, n := writeMessage(response, s.buf);
|
||||
if err != nil {
|
||||
fmt.Printf("failed to write stun response");
|
||||
} else {
|
||||
(*s.conn).WriteTo(s.buf[:n], addr);
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Sturn) handleSendIndication(msg *SturnMessage, addr net.Addr, buf []byte) {
|
||||
|
||||
peer := getAttribute(msg, ATRXorPeerAddress)
|
||||
if peer == nil {
|
||||
fmt.Println("no peer");
|
||||
return
|
||||
}
|
||||
|
||||
data := getAttribute(msg, ATRData)
|
||||
if data == nil {
|
||||
fmt.Println("no data");
|
||||
return
|
||||
}
|
||||
|
||||
s.sync.Lock();
|
||||
defer s.sync.Unlock();
|
||||
source := addr.String()
|
||||
allocation, found := s.allocations[source]
|
||||
if !found {
|
||||
fmt.Println("no allocation");
|
||||
return
|
||||
}
|
||||
|
||||
set := false
|
||||
for _, permission := range allocation.permissions {
|
||||
if permission == peer.strValue {
|
||||
address := fmt.Sprintf("%s:%d", peer.strValue, peer.intValue)
|
||||
dst, err := net.ResolveUDPAddr("udp", address)
|
||||
if err != nil {
|
||||
fmt.Println("no resolve");
|
||||
return
|
||||
}
|
||||
|
||||
set = true
|
||||
fmt.Println("stun/turn data", dst.String());
|
||||
_, err = allocation.conn.WriteTo(data.binValue, dst)
|
||||
if err != nil {
|
||||
fmt.Println("write error");
|
||||
}
|
||||
}
|
||||
}
|
||||
if !set {
|
||||
fmt.Println("dropped indication");
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Sturn) handleBindingRequest(msg *SturnMessage, addr net.Addr) {
|
||||
|
||||
address := strings.Split(addr.String(), ":")
|
||||
ip := address[0];
|
||||
port, _ := strconv.Atoi(address[1]);
|
||||
var attributes []SturnAttribute
|
||||
attributes = append(attributes, SturnAttribute{
|
||||
atrType: ATRXorMappedAddress,
|
||||
byteValue: FAMIPv4,
|
||||
intValue: int32(port),
|
||||
strValue: ip,
|
||||
});
|
||||
response := &SturnMessage{
|
||||
class: CLSResponse,
|
||||
method: MEHBinding,
|
||||
transaction: msg.transaction,
|
||||
attributes: attributes,
|
||||
};
|
||||
err, n := writeMessage(response, s.buf);
|
||||
if err != nil {
|
||||
fmt.Printf("failed to write stun response");
|
||||
} else {
|
||||
(*s.conn).WriteTo(s.buf[:n], addr);
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Sturn) handleRefreshRequest(msg *SturnMessage, addr net.Addr) {
|
||||
|
||||
response := &SturnMessage{
|
||||
class: CLSResponse,
|
||||
method: MEHRefresh,
|
||||
transaction: msg.transaction,
|
||||
attributes: []SturnAttribute{},
|
||||
};
|
||||
err, n := writeMessage(response, s.buf);
|
||||
if err != nil {
|
||||
fmt.Printf("failed to write stun response");
|
||||
} else {
|
||||
(*s.conn).WriteTo(s.buf[:n], addr);
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Sturn) setAllocation(addr net.Addr, transaction []byte, response []byte, port int, conn net.PacketConn, session *SturnSession) (*SturnAllocation) {
|
||||
source := addr.String()
|
||||
allocation := &SturnAllocation{}
|
||||
allocation.port = port
|
||||
allocation.conn = conn
|
||||
allocation.source = source
|
||||
allocation.addr = addr
|
||||
allocation.transaction = make([]byte, len(transaction))
|
||||
copy(allocation.transaction, transaction)
|
||||
allocation.response = make([]byte, len(response))
|
||||
copy(allocation.response, response)
|
||||
s.allocations[source] = allocation
|
||||
return allocation
|
||||
}
|
||||
|
||||
func (s *Sturn) getAllocation(source string, transaction []byte, session *SturnSession) (*SturnAllocation, error) {
|
||||
for _, allocation := range s.allocations {
|
||||
if allocation.source == source {
|
||||
if len(allocation.transaction) == len(transaction) {
|
||||
match := true
|
||||
for i := 0; i < len(transaction); i++ {
|
||||
if transaction[i] != allocation.transaction[i] {
|
||||
match = false
|
||||
}
|
||||
}
|
||||
if match {
|
||||
return allocation, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("5-tuple collision")
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *Sturn) handleAllocateRequest(msg *SturnMessage, addr net.Addr) {
|
||||
|
||||
username := getAttribute(msg, ATRUsername)
|
||||
if username == nil {
|
||||
fmt.Println("no username", addr.String(), msg.transaction);
|
||||
s.sendRequestError(msg, addr, 401)
|
||||
return
|
||||
}
|
||||
|
||||
s.sync.Lock();
|
||||
defer s.sync.Unlock();
|
||||
session, set := sturn.sessions[username.strValue]
|
||||
if !set {
|
||||
fmt.Println("no session", addr.String());
|
||||
s.sendRequestError(msg, addr, 401)
|
||||
return
|
||||
}
|
||||
|
||||
allocation, collision := s.getAllocation(addr.String(), msg.transaction, session)
|
||||
if collision != nil {
|
||||
fmt.Println("5tuple collision", addr.String())
|
||||
s.sendRequestError(msg, addr, 403)
|
||||
return
|
||||
}
|
||||
if allocation != nil {
|
||||
fmt.Println("dup request", addr.String())
|
||||
(*s.conn).WriteTo(allocation.response, addr)
|
||||
return
|
||||
}
|
||||
|
||||
relayPort, err := s.getRelayPort()
|
||||
if err != nil {
|
||||
fmt.Println(err);
|
||||
s.sendRequestError(msg, addr, 508)
|
||||
return
|
||||
}
|
||||
|
||||
connAddress := fmt.Sprintf(":%d", relayPort)
|
||||
conn, connErr := net.ListenPacket("udp", connAddress)
|
||||
if connErr != nil {
|
||||
s.sendRequestError(msg, addr, 500)
|
||||
return
|
||||
}
|
||||
|
||||
address := strings.Split(addr.String(), ":")
|
||||
ip := address[0];
|
||||
port, _ := strconv.Atoi(address[1]);
|
||||
var attributes []SturnAttribute
|
||||
attributes = append(attributes, SturnAttribute{
|
||||
atrType: ATRXorRelayedAddress,
|
||||
byteValue: FAMIPv4,
|
||||
intValue: int32(relayPort),
|
||||
//strValue: "192.168.13.233",
|
||||
strValue: "98.234.232.221",
|
||||
});
|
||||
attributes = append(attributes, SturnAttribute{
|
||||
atrType: ATRLifetime,
|
||||
intValue: int32(600),
|
||||
});
|
||||
attributes = append(attributes, SturnAttribute{
|
||||
atrType: ATRXorMappedAddress,
|
||||
byteValue: FAMIPv4,
|
||||
intValue: int32(port),
|
||||
strValue: ip,
|
||||
});
|
||||
attributes = append(attributes, SturnAttribute{
|
||||
atrType: ATRMessageIntegrity,
|
||||
});
|
||||
response := &SturnMessage{
|
||||
class: CLSResponse,
|
||||
method: MEHAllocate,
|
||||
transaction: msg.transaction,
|
||||
attributes: attributes,
|
||||
};
|
||||
|
||||
err, n := writeMessage(response, s.buf)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to write stun response")
|
||||
} else {
|
||||
allocation := s.setAllocation(addr, msg.transaction, s.buf[:n], relayPort, conn, session)
|
||||
(*s.conn).WriteTo(s.buf[:n], addr)
|
||||
fmt.Println("allocated: ", addr.String())
|
||||
go s.relay(allocation);
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getAttribute(msg *SturnMessage, atrType int) (attr *SturnAttribute) {
|
||||
for i, _ := range msg.attributes {
|
||||
if msg.attributes[i].atrType == atrType {
|
||||
attr = &msg.attributes[i];
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Sturn) relay(allocation *SturnAllocation) {
|
||||
data := make([]byte, SturnMaxSize)
|
||||
buf := make([]byte, SturnMaxSize)
|
||||
for {
|
||||
n, addr, err := allocation.conn.ReadFrom(data)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
// CLEANUP ALLOCATION
|
||||
return
|
||||
}
|
||||
|
||||
s.sync.Lock();
|
||||
split := strings.Split(addr.String(), ":")
|
||||
ip := split[0]
|
||||
port, _ := strconv.Atoi(split[1]);
|
||||
set := false
|
||||
for _, permission := range allocation.permissions {
|
||||
if permission == ip {
|
||||
|
||||
var attributes []SturnAttribute
|
||||
attributes = append(attributes, SturnAttribute{
|
||||
atrType: ATRXorPeerAddress,
|
||||
strValue: ip,
|
||||
intValue: int32(port),
|
||||
})
|
||||
attributes = append(attributes, SturnAttribute{
|
||||
atrType: ATRData,
|
||||
binValue: data[:n],
|
||||
})
|
||||
|
||||
relay := &SturnMessage{
|
||||
class: CLSIndication,
|
||||
method: MEHData,
|
||||
transaction: []byte{ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 },
|
||||
attributes: attributes,
|
||||
};
|
||||
|
||||
err, l := writeMessage(relay, buf)
|
||||
if err != nil {
|
||||
fmt.Println("no resolve");
|
||||
} else {
|
||||
fmt.Println("---- stun/turn relay", allocation.addr.String());
|
||||
_, err := allocation.conn.WriteTo(buf[:l], allocation.addr);
|
||||
set = true
|
||||
if err != nil {
|
||||
fmt.Println("writeto failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !set {
|
||||
fmt.Println("dropped relay");
|
||||
}
|
||||
s.sync.Unlock();
|
||||
}
|
||||
}
|
||||
|
@ -1,171 +0,0 @@
|
||||
package sturn
|
||||
|
||||
import (
|
||||
// "encoding/json"
|
||||
"encoding/hex"
|
||||
"sync"
|
||||
"github.com/theckman/go-securerandom"
|
||||
// "time"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
var sturn *Sturn
|
||||
const SturnKeepAlive = 3600
|
||||
const SturnMaxSize = 1024
|
||||
const SturnMaxBindFail = 16
|
||||
const SturnNonceSize = 8
|
||||
const SturnPassSize = 8
|
||||
|
||||
type SturnAllocation struct {
|
||||
source string
|
||||
transaction []byte
|
||||
response []byte
|
||||
port int
|
||||
permissions []string
|
||||
conn net.PacketConn
|
||||
addr net.Addr
|
||||
}
|
||||
|
||||
type SturnSession struct {
|
||||
user string
|
||||
auth string
|
||||
relayPorts []int
|
||||
}
|
||||
|
||||
type Sturn struct {
|
||||
sync sync.Mutex
|
||||
sessionId int
|
||||
sessions map[string]*SturnSession
|
||||
closing bool
|
||||
port int
|
||||
conn *net.PacketConn
|
||||
closed chan bool
|
||||
buf []byte
|
||||
publicIp string
|
||||
relayStart int
|
||||
relayCount int
|
||||
relayPorts map[int]bool
|
||||
relayIndex int
|
||||
allocations map[string]*SturnAllocation
|
||||
}
|
||||
|
||||
func Listen(port int, relayStart int, relayCount int) (error) {
|
||||
|
||||
if (sturn != nil) {
|
||||
(*sturn.conn).Close()
|
||||
<-sturn.closed
|
||||
sturn = nil
|
||||
}
|
||||
|
||||
address := fmt.Sprintf(":%d", port)
|
||||
conn, err := net.ListenPacket("udp", address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
relayPorts := make(map[int]bool)
|
||||
for i := 0; i < relayCount; i++ {
|
||||
relayPorts[i] = true
|
||||
}
|
||||
|
||||
sturn = &Sturn{
|
||||
sessionId: 0,
|
||||
closing: false,
|
||||
port: port,
|
||||
relayStart: relayStart,
|
||||
relayCount: relayCount,
|
||||
relayPorts: relayPorts,
|
||||
conn: &conn,
|
||||
buf: make([]byte, SturnMaxSize),
|
||||
sessions: make(map[string]*SturnSession),
|
||||
allocations: make(map[string]*SturnAllocation),
|
||||
}
|
||||
|
||||
go sturn.serve(conn);
|
||||
return nil
|
||||
}
|
||||
|
||||
func Close() {
|
||||
if (sturn != nil) {
|
||||
(*sturn.conn).Close()
|
||||
<-sturn.closed
|
||||
sturn = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Sturn) serve(conn net.PacketConn) {
|
||||
for {
|
||||
buf := make([]byte, SturnMaxSize)
|
||||
n, addr, err := conn.ReadFrom(buf)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
s.handleMessage(buf[:n], addr);
|
||||
}
|
||||
|
||||
s.sync.Lock()
|
||||
s.closing = true
|
||||
for _, session := range s.sessions {
|
||||
// TODO cleanup session
|
||||
fmt.Println(session)
|
||||
}
|
||||
s.sync.Unlock()
|
||||
|
||||
s.closed <- true
|
||||
}
|
||||
|
||||
func TestSession() {
|
||||
if sturn != nil {
|
||||
sturn.sync.Lock()
|
||||
defer sturn.sync.Unlock()
|
||||
if sturn.closing {
|
||||
return
|
||||
}
|
||||
session := &SturnSession{
|
||||
user: "user",
|
||||
auth: "pass",
|
||||
}
|
||||
sturn.sessions["user"] = session
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Sturn) addSession() (*SturnSession, error) {
|
||||
s.sync.Lock()
|
||||
defer s.sync.Unlock()
|
||||
if !s.closing {
|
||||
return nil, errors.New("closing sturn")
|
||||
}
|
||||
s.sessionId += 1
|
||||
user := fmt.Sprintf("%08d", s.sessionId)
|
||||
authBin, authErr := securerandom.Bytes(SturnPassSize)
|
||||
if authErr != nil {
|
||||
return nil, authErr
|
||||
}
|
||||
session := &SturnSession{
|
||||
user: user,
|
||||
auth: hex.EncodeToString(authBin),
|
||||
}
|
||||
s.sessions[user] = session
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (s *Sturn) getRelayPort() (int, error) {
|
||||
s.relayIndex += 1;
|
||||
for i := 0; i < s.relayCount; i++ {
|
||||
key := (i + s.relayIndex) % s.relayCount;
|
||||
if s.relayPorts[key] {
|
||||
s.relayPorts[key] = false
|
||||
return s.relayStart + key, nil
|
||||
}
|
||||
}
|
||||
return 0, errors.New("no available relay port")
|
||||
}
|
||||
|
||||
func (s *Sturn) setRelayPort(port int) {
|
||||
key := port - s.relayStart
|
||||
s.relayPorts[key] = true
|
||||
}
|
||||
|
@ -1,334 +0,0 @@
|
||||
package sturn
|
||||
|
||||
const CLSUnknown = 0
|
||||
const CLSRequest = 1
|
||||
const CLSResponse = 2
|
||||
const CLSError = 3
|
||||
const CLSIndication = 4
|
||||
|
||||
const ATRUnknown = 0
|
||||
const ATRMappedAddress = 1
|
||||
const ATRUsername = 2
|
||||
const ATRMessageIntegrity = 3
|
||||
const ATRErrorCode = 4
|
||||
const ATRUnknownAttributes = 5
|
||||
const ATRRealm = 6
|
||||
const ATRNonce = 7
|
||||
const ATRXorMappedAddress = 8
|
||||
const ATRSoftware = 9
|
||||
const ATRAlternateServer = 10
|
||||
const ATRFingerprint = 11
|
||||
const ATRMessageIntegritySha256 = 12
|
||||
const ATRPasswordAlgorithm = 13
|
||||
const ATRUserHash = 14
|
||||
const ATRPasswordAlgorithms = 15
|
||||
const ATRAlternateDomain = 16
|
||||
const ATRChannelNumber = 17
|
||||
const ATRLifetime = 18
|
||||
const ATRXorPeerAddress = 19
|
||||
const ATRData = 20
|
||||
const ATRXorRelayedAddress = 21
|
||||
const ATREvenPort = 22
|
||||
const ATRRequestedTransport = 23
|
||||
const ATRDontFragment = 24
|
||||
const ATRReservationToken = 25
|
||||
const ATRAdditionalAddressFamily = 26
|
||||
const ATRAddressErrorCode = 27
|
||||
const ATRAddressIcmp = 28
|
||||
const ATRRequestedAddressFamily = 29
|
||||
|
||||
const MEHUnknown = 0
|
||||
const MEHBinding = 1
|
||||
const MEHAllocate = 2
|
||||
const MEHRefresh = 3
|
||||
const MEHSend = 4
|
||||
const MEHData = 5
|
||||
const MEHCreatePermission = 6
|
||||
const MEHChannelBind = 7
|
||||
|
||||
const FAMIPv4 = 1
|
||||
const FAMIPv6 = 2
|
||||
|
||||
type SturnAttribute struct {
|
||||
atrType int
|
||||
byteValue byte
|
||||
strValue string
|
||||
intValue int32
|
||||
binValue []byte
|
||||
}
|
||||
|
||||
type SturnMessage struct {
|
||||
class int
|
||||
method int
|
||||
transaction []byte
|
||||
attributes []SturnAttribute
|
||||
}
|
||||
|
||||
func getMessageType(b0 byte, b1 byte) (int, int) {
|
||||
|
||||
if b0 == 0x00 && b1 == 0x01 {
|
||||
return CLSRequest, MEHBinding
|
||||
}
|
||||
if b0 == 0x01 && b1 == 0x01 {
|
||||
return CLSResponse, MEHBinding
|
||||
}
|
||||
if b0 == 0x01 && b1 == 0x11 {
|
||||
return CLSError, MEHBinding
|
||||
}
|
||||
if b0 == 0x00 && b1 == 0x03 {
|
||||
return CLSRequest, MEHAllocate
|
||||
}
|
||||
if b0 == 0x01 && b1 == 0x03 {
|
||||
return CLSResponse, MEHAllocate
|
||||
}
|
||||
if b0 == 0x01 && b1 == 0x13 {
|
||||
return CLSError, MEHAllocate
|
||||
}
|
||||
if b0 == 0x00 && b1 == 0x04 {
|
||||
return CLSRequest, MEHRefresh
|
||||
}
|
||||
if b0 == 0x01 && b1 == 0x04 {
|
||||
return CLSResponse, MEHRefresh
|
||||
}
|
||||
if b0 == 0x01 && b1 == 0x14 {
|
||||
return CLSError, MEHRefresh
|
||||
}
|
||||
if b0 == 0x00 && b1 == 0x08 {
|
||||
return CLSRequest, MEHCreatePermission
|
||||
}
|
||||
if b0 == 0x01 && b1 == 0x08 {
|
||||
return CLSResponse, MEHCreatePermission
|
||||
}
|
||||
if b0 == 0x01 && b1 == 0x18 {
|
||||
return CLSError, MEHCreatePermission
|
||||
}
|
||||
if b0 == 0x00 && b1 == 0x09 {
|
||||
return CLSRequest, MEHChannelBind
|
||||
}
|
||||
if b0 == 0x01 && b1 == 0x09 {
|
||||
return CLSResponse, MEHChannelBind
|
||||
}
|
||||
if b0 == 0x01 && b1 == 0x19 {
|
||||
return CLSError, MEHChannelBind
|
||||
}
|
||||
if b0 == 0x00 && b1 == 0x16 {
|
||||
return CLSIndication, MEHSend
|
||||
}
|
||||
if b0 == 0x00 && b1 == 0x17 {
|
||||
return CLSIndication, MEHData
|
||||
}
|
||||
return CLSUnknown, MEHUnknown
|
||||
}
|
||||
|
||||
func setMessageType(class int, method int) (byte, byte) {
|
||||
if class == CLSRequest && method == MEHBinding {
|
||||
return 0x00, 0x01
|
||||
}
|
||||
if class == CLSResponse && method == MEHBinding {
|
||||
return 0x01, 0x01
|
||||
}
|
||||
if class == CLSError && method == MEHBinding {
|
||||
return 0x01, 0x11
|
||||
}
|
||||
if class == CLSRequest && method == MEHAllocate {
|
||||
return 0x00, 0x03
|
||||
}
|
||||
if class == CLSResponse && method == MEHAllocate {
|
||||
return 0x01, 0x03
|
||||
}
|
||||
if class == CLSError && method == MEHAllocate {
|
||||
return 0x01, 0x13
|
||||
}
|
||||
if class == CLSResponse && method == MEHCreatePermission {
|
||||
return 0x01, 0x08
|
||||
}
|
||||
if class == CLSError && method == MEHCreatePermission {
|
||||
return 0x01, 0x18
|
||||
}
|
||||
if class == CLSIndication && method == MEHData {
|
||||
return 0x00, 0x17
|
||||
}
|
||||
return 0x00, 0x00
|
||||
}
|
||||
|
||||
func getAttributeType(b0 byte, b1 byte) (int) {
|
||||
if b1 == 0x01 && b0 == 0x00 {
|
||||
return ATRMappedAddress
|
||||
}
|
||||
if b1 == 0x06 && b0 == 0x00 {
|
||||
return ATRUsername
|
||||
}
|
||||
if b1 == 0x08 && b0 == 0x00 {
|
||||
return ATRMessageIntegrity
|
||||
}
|
||||
if b1 == 0x09 && b0 == 0x00 {
|
||||
return ATRErrorCode
|
||||
}
|
||||
if b1 == 0x0A && b0 == 0x00 {
|
||||
return ATRUnknownAttributes
|
||||
}
|
||||
if b1 == 0x14 && b0 == 0x00 {
|
||||
return ATRRealm
|
||||
}
|
||||
if b1 == 0x15 && b0 == 0x00 {
|
||||
return ATRNonce
|
||||
}
|
||||
if b1 == 0x20 && b0 == 0x00 {
|
||||
return ATRXorMappedAddress
|
||||
}
|
||||
if b1 == 0x22 && b0 == 0x80 {
|
||||
return ATRSoftware
|
||||
}
|
||||
if b1 == 0x23 && b0 == 0x80 {
|
||||
return ATRAlternateServer
|
||||
}
|
||||
if b1 == 0x28 && b0 == 0x80 {
|
||||
return ATRFingerprint
|
||||
}
|
||||
if b1 == 0x1C && b0 == 0x00 {
|
||||
return ATRMessageIntegritySha256
|
||||
}
|
||||
if b1 == 0x1D && b0 == 0x00 {
|
||||
return ATRPasswordAlgorithms
|
||||
}
|
||||
if b1 == 0x1E && b0 == 0x00 {
|
||||
return ATRUserHash
|
||||
}
|
||||
if b1 == 0x02 && b0 == 0x80 {
|
||||
return ATRPasswordAlgorithms
|
||||
}
|
||||
if b1 == 0x03 && b0 == 0x80 {
|
||||
return ATRAlternateDomain
|
||||
}
|
||||
if b1 == 0x0C && b0 == 0x00 {
|
||||
return ATRChannelNumber
|
||||
}
|
||||
if b1 == 0x0D && b0 == 0x00 {
|
||||
return ATRLifetime
|
||||
}
|
||||
if b1 == 0x12 && b0 == 0x00 {
|
||||
return ATRXorPeerAddress
|
||||
}
|
||||
if b1 == 0x13 && b0 == 0x00 {
|
||||
return ATRData
|
||||
}
|
||||
if b1 == 0x16 && b0 == 0x00 {
|
||||
return ATRXorRelayedAddress
|
||||
}
|
||||
if b1 == 0x17 && b0 == 0x00 {
|
||||
return ATRRequestedAddressFamily
|
||||
}
|
||||
if b1 == 0x18 && b0 == 0x00 {
|
||||
return ATREvenPort
|
||||
}
|
||||
if b1 == 0x19 && b0 == 0x00 {
|
||||
return ATRRequestedTransport
|
||||
}
|
||||
if b1 == 0x1A && b0 == 0x00 {
|
||||
return ATRDontFragment
|
||||
}
|
||||
if b1 == 0x22 && b0 == 0x00 {
|
||||
return ATRReservationToken
|
||||
}
|
||||
if b1 == 0x00 && b0 == 0x80 {
|
||||
return ATRAdditionalAddressFamily
|
||||
}
|
||||
if b1 == 0x01 && b0 == 0x80 {
|
||||
return ATRAddressErrorCode
|
||||
}
|
||||
if b1 == 0x04 && b0 == 0x80 {
|
||||
return ATRAddressIcmp
|
||||
}
|
||||
return ATRUnknown
|
||||
}
|
||||
|
||||
func setAttributeType(atrType int) (byte, byte) {
|
||||
if atrType == ATRMappedAddress {
|
||||
return 0x01, 0x00
|
||||
}
|
||||
if atrType == ATRUsername {
|
||||
return 0x06, 0x00
|
||||
}
|
||||
if atrType == ATRMessageIntegrity {
|
||||
return 0x08, 0x00
|
||||
}
|
||||
if atrType == ATRErrorCode {
|
||||
return 0x09, 0x00
|
||||
}
|
||||
if atrType == ATRUnknownAttributes {
|
||||
return 0x0A, 0x00
|
||||
}
|
||||
if atrType == ATRRealm {
|
||||
return 0x14, 0x00
|
||||
}
|
||||
if atrType == ATRNonce {
|
||||
return 0x15, 0x00
|
||||
}
|
||||
if atrType == ATRXorMappedAddress {
|
||||
return 0x20, 0x00
|
||||
}
|
||||
if atrType == ATRSoftware {
|
||||
return 0x22, 0x80
|
||||
}
|
||||
if atrType == ATRAlternateServer {
|
||||
return 0x23, 0x80
|
||||
}
|
||||
if atrType == ATRFingerprint {
|
||||
return 0x28, 0x80
|
||||
}
|
||||
if atrType == ATRMessageIntegritySha256 {
|
||||
return 0x1C, 0x00
|
||||
}
|
||||
if atrType == ATRPasswordAlgorithms {
|
||||
return 0x1D, 0x00
|
||||
}
|
||||
if atrType == ATRUserHash {
|
||||
return 0x1E, 0x00
|
||||
}
|
||||
if atrType == ATRPasswordAlgorithms {
|
||||
return 0x02, 0x80
|
||||
}
|
||||
if atrType == ATRAlternateDomain {
|
||||
return 0x03, 0x80
|
||||
}
|
||||
if atrType == ATRChannelNumber {
|
||||
return 0x0C, 0x00
|
||||
}
|
||||
if atrType == ATRLifetime {
|
||||
return 0x0D, 0x00
|
||||
}
|
||||
if atrType == ATRXorPeerAddress {
|
||||
return 0x12, 0x00
|
||||
}
|
||||
if atrType == ATRData {
|
||||
return 0x13, 0x00
|
||||
}
|
||||
if atrType == ATRXorRelayedAddress {
|
||||
return 0x16, 0x00
|
||||
}
|
||||
if atrType == ATRRequestedAddressFamily {
|
||||
return 0x17, 0x00
|
||||
}
|
||||
if atrType == ATREvenPort {
|
||||
return 0x18, 0x00
|
||||
}
|
||||
if atrType == ATRRequestedTransport {
|
||||
return 0x19, 0x00
|
||||
}
|
||||
if atrType == ATRDontFragment {
|
||||
return 0x1A, 0x00
|
||||
}
|
||||
if atrType == ATRReservationToken {
|
||||
return 0x22, 0x00
|
||||
}
|
||||
if atrType == ATRAdditionalAddressFamily {
|
||||
return 0x00, 0x80
|
||||
}
|
||||
if atrType == ATRAddressErrorCode {
|
||||
return 0x01, 0x80
|
||||
}
|
||||
if atrType == ATRAddressIcmp {
|
||||
return 0x04, 0x80
|
||||
}
|
||||
return 0x00, 0x00
|
||||
}
|
Loading…
Reference in New Issue
Block a user