carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package host
2
3import (
4 "net"
5 "os"
6 "path/filepath"
7 "strconv"
8 "strings"
9
10 "github.com/carlosframework/platform/internal/instancectl"
11 "github.com/carlosframework/platform/internal/provision"
12)
13
14func claimBoundUnitDefinition(s claimUnitShape) ([]byte, error) {
15 if !s.valid() || !claimHexDigest(s.Program) {
16 return nil, os.ErrPermission
17 }
18 template := claimBoundTemplate
19 body := strings.ReplaceAll(strings.ReplaceAll(string(template), "%i", instancectl.Escape(provision.InstanceID(s.Host))), "%I", provision.InstanceID(s.Host))
20 // With no live root gate, even a direct systemctl restart must execute no
21 // tenant code. The temporary reservation drop-in replaces this command.
22 body = strings.Replace(body, "ExecStart="+instancectl.SystemBinary+" instance-exec run "+provision.InstanceID(s.Host), "ExecStart=/usr/bin/false", 1)
23 if s.Socket != "" && s.Socket != provision.NestedSocket(s.Host) {
24 if !claimFlatSocket(s) {
25 return nil, os.ErrPermission
26 }
27 body = strings.Replace(body, "TemporaryFileSystem=/run/carlos:ro\n", "", 1)
28 body += "\n[Service]\nBindPaths=" + provision.InstanceRunDir(s.Host) + ":/run/carlos\nReadWritePaths=/run/carlos\n"
29 }
30 if s.Addr != "" {
31 host, port, err := net.SplitHostPort(s.Addr)
32 n, e := strconv.Atoi(port)
33 if err != nil || e != nil || n < 1 || n > 65535 {
34 return nil, os.ErrPermission
35 }
36 family, bits := "ipv4", "/32"
37 if ip4 := net.ParseIP(host).To4(); ip4 != nil {
38 host = ip4.String()
39 } else {
40 family, bits = "ipv6", "/128"
41 }
42 body += "\n[Service]\nIPAddressAllow=" + host + bits + "\nSocketBindDeny=any\nSocketBindAllow=" + family + ":tcp:" + port + "\n"
43 }
44 return []byte(body), nil
45}
46
47func claimFlatSocket(s claimUnitShape) bool {
48 if filepath.Dir(s.Socket) != provision.SocketDir || !strings.HasSuffix(s.Socket, ".sock") {
49 return false
50 }
51 for _, r := range filepath.Base(s.Socket) {
52 if !(r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9' || r == '-' || r == '_' || r == '.') {
53 return false
54 }
55 }
56 return true
57}
58
59func claimSocketTarget(s claimUnitShape) string {
60 if claimFlatSocket(s) {
61 return filepath.Join(provision.InstanceRunDir(s.Host), filepath.Base(s.Socket))
62 }
63 return s.Socket
64}
65