1package main 2 3import ( 4 "flag" 5 "log" 6 "net" 7 "os" 8 "os/signal" 9 "regexp" 10 "strconv" 11 "syscall" 12 13 "github.com/pion/turn/v2" 14) 15 16func main() { 17 publicIP := flag.String("public-ip", "", "IP Address that TURN can be contacted by.") 18 port := flag.Int("port", 3478, "Listening port.") 19 users := flag.String("users", "", "List of username and password (e.g. \"user=pass,user=pass\")") 20 realm := flag.String("realm", "pion.ly", "Realm (defaults to \"pion.ly\")") 21 flag.Parse() 22 23 if len(*publicIP) == 0 { 24 log.Fatalf("'public-ip' is required") 25 } else if len(*users) == 0 { 26 log.Fatalf("'users' is required") 27 } 28 29 // Create a TCP listener to pass into pion/turn 30 // pion/turn itself doesn't allocate any TCP listeners, but lets the user pass them in 31 // this allows us to add logging, storage or modify inbound/outbound traffic 32 tcpListener, err := net.Listen("tcp4", "0.0.0.0:"+strconv.Itoa(*port)) 33 if err != nil { 34 log.Panicf("Failed to create TURN server listener: %s", err) 35 } 36 37 // Cache -users flag for easy lookup later 38 // If passwords are stored they should be saved to your DB hashed using turn.GenerateAuthKey 39 usersMap := map[string][]byte{} 40 for _, kv := range regexp.MustCompile(`(\w+)=(\w+)`).FindAllStringSubmatch(*users, -1) { 41 usersMap[kv[1]] = turn.GenerateAuthKey(kv[1], *realm, kv[2]) 42 } 43 44 s, err := turn.NewServer(turn.ServerConfig{ 45 Realm: *realm, 46 // Set AuthHandler callback 47 // This is called everytime a user tries to authenticate with the TURN server 48 // Return the key for that user, or false when no user is found 49 AuthHandler: func(username string, realm string, srcAddr net.Addr) ([]byte, bool) { 50 if key, ok := usersMap[username]; ok { 51 return key, true 52 } 53 return nil, false 54 }, 55 // ListenerConfig is a list of Listeners and the configuration around them 56 ListenerConfigs: []turn.ListenerConfig{ 57 { 58 Listener: tcpListener, 59 RelayAddressGenerator: &turn.RelayAddressGeneratorStatic{ 60 RelayAddress: net.ParseIP(*publicIP), 61 Address: "0.0.0.0", 62 }, 63 }, 64 }, 65 }) 66 if err != nil { 67 log.Panic(err) 68 } 69 70 // Block until user sends SIGINT or SIGTERM 71 sigs := make(chan os.Signal, 1) 72 signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) 73 <-sigs 74 75 if err = s.Close(); err != nil { 76 log.Panic(err) 77 } 78} 79