Welcome to mirror list, hosted at ThFree Co, Russian Federation.

register.go « grumble « cmd - github.com/mumble-voip/grumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 50015a83c98573e05bf683da3436fc069b31e063 (plain)
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
// Copyright (c) 2011 The Grumble Authors
// The use of this source code is goverened by a BSD-style
// license that can be found in the LICENSE-file.

package main

// This file handles public server list registration

import (
	"bytes"
	"crypto/sha1"
	"crypto/tls"
	"encoding/hex"
	"encoding/xml"
	"io/ioutil"
	"net/http"
)

type Register struct {
	XMLName  xml.Name `xml:"server"`
	Version  string   `xml:"version"`
	Release  string   `xml:"release"`
	Name     string   `xml:"name"`
	Host     string   `xml:"host"`
	Password string   `xml:"password"`
	Port     int      `xml:"port"`
	Url      string   `xml:"url"`
	Digest   string   `xml:"digest"`
	Users    int      `xml:"users"`
	Channels int      `xml:"channels"`
	Location string   `xml:"location"`
}

const registerUrl = "https://mumble.info/register.cgi"

// Determines whether a server is public by checking whether the
// config values required for public registration are set.
//
// This function is used to determine whether or not to periodically
// contact the master server list and update this server's metadata.
func (server *Server) IsPublic() bool {
	if len(server.cfg.StringValue("RegisterName")) == 0 {
		return false
	}
	if len(server.cfg.StringValue("RegisterHost")) == 0 {
		return false
	}
	if len(server.cfg.StringValue("RegisterPassword")) == 0 {
		return false
	}
	if len(server.cfg.StringValue("RegisterWebUrl")) == 0 {
		return false
	}
	return true
}

// Perform a public server registration update.
//
// When a Mumble server connects to the master server
// for registration, it connects using its server certificate
// as a client certificate for authentication purposes.
func (server *Server) RegisterPublicServer() {
	if !server.IsPublic() {
		return
	}

	// Fetch the server's certificates and put them in a tls.Config.
	// We need the certificate chain to be able to use it in our client
	// certificate chain to the registration server, and we also need to
	// include a digest of the leaf certiifcate in the registration XML document
	// we send off to the server.
	config := &tls.Config{}
	for _, cert := range server.tlscfg.Certificates {
		config.Certificates = append(config.Certificates, cert)
	}

	hasher := sha1.New()
	hasher.Write(config.Certificates[0].Certificate[0])
	digest := hex.EncodeToString(hasher.Sum(nil))

	// Render registration XML template
	reg := Register{
		Name:     server.cfg.StringValue("RegisterName"),
		Host:     server.cfg.StringValue("RegisterHost"),
		Password: server.cfg.StringValue("RegisterPassword"),
		Url:      server.cfg.StringValue("RegisterWebUrl"),
		Location: server.cfg.StringValue("RegisterLocation"),
		Port:     server.CurrentPort(),
		Digest:   digest,
		Users:    len(server.clients),
		Channels: len(server.Channels),
		Version:  "1.2.4",
		Release:  "Grumble Git",
	}
	buf := bytes.NewBuffer(nil)
	err := xml.NewEncoder(buf).Encode(reg)
	if err != nil {
		server.Printf("register: unable to marshal xml: %v", err)
		return
	}

	// Post registration XML data to server asynchronously in its own goroutine
	go func() {
		tr := &http.Transport{
			TLSClientConfig: config,
		}
		client := &http.Client{Transport: tr}
		r, err := client.Post(registerUrl, "text/xml", ioutil.NopCloser(buf))
		if err != nil {
			server.Printf("register: unable to post registration request: %v", err)
			return
		}
		bodyBytes, err := ioutil.ReadAll(r.Body)
		if err == nil {
			registerMsg := string(bodyBytes)
			if r.StatusCode == 200 {
				server.Printf("register: %v", registerMsg)
			} else {
				server.Printf("register: (status %v) %v", r.StatusCode, registerMsg)
			}
		} else {
			server.Printf("register: unable to read post response: %v", err)
			return
		}
	}()
}