-
Notifications
You must be signed in to change notification settings - Fork 275
/
uds.go
119 lines (103 loc) · 3.04 KB
/
uds.go
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
//
// Copyright The Athenz Authors
//
// 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.
//
package sds
import (
"fmt"
"inet.af/peercred"
"log"
"net"
"os"
"path/filepath"
"strconv"
)
type Listener struct {
net.Listener
}
type UdsConn struct {
net.Conn
ClientInfo ClientInfo
}
// StartUdsListener Start a Unix-Domain-Socket listener. We're going to create a simple
// wrapper struct for the Listener object since we want to intercept Accept calls
// and extract the caller's user and process ids. The client info object will then
// be passed to grpc as credentials.AuthInfo which can be accessed later from the
// stream context
func StartUdsListener(udsPath string) (net.Listener, error) {
err := os.MkdirAll(filepath.Dir(udsPath), 0755)
if err != nil {
return nil, fmt.Errorf("failed to make the directory for the Unix-Domain-Socket listener on path %q: %v", udsPath, err)
}
// Prepare: delete any existing Unix-Domain-Socket.
os.Remove(udsPath)
// Listen on the Unix-Domain-Socket.
udsListener, err := net.Listen("unix", udsPath)
if err != nil {
return nil, fmt.Errorf("failed to listed to Unix-Domain-Socket listener on path %q: %v", udsPath, err)
}
err = os.Chmod(udsPath, os.ModePerm)
if err != nil {
udsListener.Close()
return nil, fmt.Errorf("failed to set permissions to Unix-Domain-Socket on path %q: %v", udsPath, err)
}
// Server is ready to accept UDS requests.
log.Printf("Unix-Domain-Socket listener is ready on path: %s\n", udsPath)
return &Listener{
Listener: udsListener,
}, nil
}
func (listener *Listener) Accept() (net.Conn, error) {
for {
conn, err := listener.Listener.Accept()
if err != nil {
return conn, err
}
return &UdsConn{
Conn: conn,
ClientInfo: getUdsUserDetails(conn),
}, nil
}
}
func (listener *Listener) Close() error {
return listener.Listener.Close()
}
func (listener *Listener) Addr() net.Addr {
return listener.Listener.Addr()
}
// Get the Unix-Domain-Socket's user and process ids
func getUdsUserDetails(connection net.Conn) ClientInfo {
var clientInfo ClientInfo
// Get uid from UDS connection.
credentials, err := peercred.Get(connection)
if err != nil {
return clientInfo
}
userId, ok := credentials.UserID()
if !ok {
log.Println("unable to obtain connection user id")
} else {
uid, err := strconv.Atoi(userId)
if err != nil {
log.Printf("unable to obtain convert user id: %s, %v\n", userId, err)
} else {
clientInfo.UserID = uid
}
}
clientInfo.PID, ok = credentials.PID()
if !ok {
log.Println("unable to obtain connection pid")
}
return clientInfo
}