File: main.go

package info (click to toggle)
golang-github-pion-dtls-v3 3.0.7-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 2,124 kB
  • sloc: makefile: 4
file content (134 lines) | stat: -rw-r--r-- 4,329 bytes parent folder | download
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
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

// Package main implements an example DTLS server which verifies client certificates.
// It also implements a basic Brute Force Attack protection.
package main

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"net"
	"sync"
	"time"

	"github.com/pion/dtls/v3"
	"github.com/pion/dtls/v3/examples/util"
)

func main() {
	// Prepare the IP to connect to
	addr := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 4444}

	//
	// Everything below is the pion-DTLS API! Thanks for using it ❤️.
	//

	// ************ Variables used to implement a basic Brute Force Attack protection *************
	var (
		attempts        = make(map[string]int) // Map of attempts for each IP address.
		attemptsMutex   sync.Mutex             // Mutex for the map of attempts.
		attemptsCleaner = time.Now()           // Time to be able to clean the map of attempts every X minutes.
	)

	certificate, err := util.LoadKeyAndCertificate("examples/certificates/server.pem",
		"examples/certificates/server.pub.pem")
	util.Check(err)

	rootCertificate, err := util.LoadCertificate("examples/certificates/server.pub.pem")
	util.Check(err)
	certPool := x509.NewCertPool()
	cert, err := x509.ParseCertificate(rootCertificate.Certificate[0])
	util.Check(err)
	certPool.AddCert(cert)

	// Prepare the configuration of the DTLS connection
	config := &dtls.Config{
		Certificates:         []tls.Certificate{certificate},
		ExtendedMasterSecret: dtls.RequireExtendedMasterSecret,
		ClientAuth:           dtls.RequireAndVerifyClientCert,
		ClientCAs:            certPool,
		// This function will be called on each connection attempt.
		OnConnectionAttempt: func(addr net.Addr) error {
			// *************** Brute Force Attack protection ***************
			// Check if the IP address is in the map, and if the IP address has exceeded the limit
			attemptsMutex.Lock()
			defer attemptsMutex.Unlock()
			// Here I implement a time cleaner for the map of attempts, every 5 minutes I will
			// decrement by 1 the number of attempts for each IP address.
			if time.Now().After(attemptsCleaner.Add(time.Minute * 5)) {
				attemptsCleaner = time.Now()
				for k, v := range attempts {
					if v > 0 {
						attempts[k]--
					}
					if attempts[k] == 0 {
						delete(attempts, k)
					}
				}
			}
			// Check if the IP address is in the map, and the IP address has exceeded the limit (Brute Force Attack protection)
			attemptIP := addr.(*net.UDPAddr).IP.String() //nolint
			if attempts[attemptIP] > 10 {
				return fmt.Errorf("too many attempts from this IP address") //nolint
			}
			// Here I increment the number of attempts for this IP address (Brute Force Attack protection)
			attempts[attemptIP]++
			// *************** END Brute Force Attack protection END ***************
			return nil
		},
	}

	// Connect to a DTLS server
	listener, err := dtls.Listen("udp", addr, config)
	util.Check(err)
	defer func() {
		util.Check(listener.Close())
	}()

	fmt.Println("Listening")

	// Simulate a chat session
	hub := util.NewHub()

	go func() {
		for {
			// Wait for a connection.
			conn, err := listener.Accept()
			util.Check(err)
			// defer conn.Close() // TODO: graceful shutdown

			// `conn` is of type `net.Conn` but may be casted to `dtls.Conn`
			// using `dtlsConn := conn.(*dtls.Conn)` in order to to expose
			// functions like `ConnectionState` etc.

			// *************** Brute Force Attack protection ***************
			// Here I decrease the number of attempts for this IP address
			attemptsMutex.Lock()
			attemptIP := conn.(*dtls.Conn).RemoteAddr().(*net.UDPAddr).IP.String() //nolint
			attempts[attemptIP]--
			// If the number of attempts for this IP address is 0, I delete the IP address from the map
			if attempts[attemptIP] == 0 {
				delete(attempts, attemptIP)
			}
			attemptsMutex.Unlock()
			// *************** END Brute Force Attack protection END ***************

			// Perform the handshake with a 30-second timeout
			ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
			dtlsConn, ok := conn.(*dtls.Conn)
			if ok {
				util.Check(dtlsConn.HandshakeContext(ctx))
			}
			cancel()

			// Register the connection with the chat hub
			hub.Register(conn)
		}
	}()

	// Start chatting
	hub.Chat()
}