diff --git a/Dockerfile b/Dockerfile index 49a0075f..f83c786b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,8 +45,8 @@ ENV VPNSP=pia \ OPENVPN_TARGET_IP= \ OPENVPN_IPV6=off \ TZ= \ - UID=1000 \ - GID=1000 \ + PUID= \ + PGID= \ PUBLICIP_FILE="/tmp/gluetun/ip" \ # PIA, Windscribe, Surfshark, Cyberghost, Vyprvpn, NordVPN, PureVPN only USER= \ diff --git a/cmd/gluetun/main.go b/cmd/gluetun/main.go index f07a2e15..e0988c8e 100644 --- a/cmd/gluetun/main.go +++ b/cmd/gluetun/main.go @@ -131,16 +131,19 @@ func _main(background context.Context, buildInfo models.BuildInformation, } // Should never change - uid, gid := allSettings.System.UID, allSettings.System.GID + puid, pgid := allSettings.System.PUID, allSettings.System.PGID const defaultUsername = "nonrootuser" - nonRootUsername, err := alpineConf.CreateUser(defaultUsername, uid) + nonRootUsername, err := alpineConf.CreateUser(defaultUsername, puid) if err != nil { logger.Error(err) return 1 } + if nonRootUsername != defaultUsername { + logger.Info("using existing username %s corresponding to user id %d", nonRootUsername, puid) + } - if err := os.Chown("/etc/unbound", uid, gid); err != nil { + if err := os.Chown("/etc/unbound", puid, pgid); err != nil { logger.Error(err) return 1 } @@ -233,7 +236,7 @@ func _main(background context.Context, buildInfo models.BuildInformation, go collectStreamLines(ctx, streamMerger, logger, signalTunnelReady) - openvpnLooper := openvpn.NewLooper(allSettings.OpenVPN, nonRootUsername, uid, gid, allServers, + openvpnLooper := openvpn.NewLooper(allSettings.OpenVPN, nonRootUsername, puid, pgid, allServers, ovpnConf, firewallConf, routingConf, logger, httpClient, os.OpenFile, streamMerger, cancel) wg.Add(1) // wait for restartOpenvpn @@ -245,13 +248,13 @@ func _main(background context.Context, buildInfo models.BuildInformation, // wait for updaterLooper.Restart() or its ticket launched with RunRestartTicker go updaterLooper.Run(ctx, wg) - unboundLooper := dns.NewLooper(dnsConf, allSettings.DNS, logger, streamMerger, nonRootUsername, uid, gid) + unboundLooper := dns.NewLooper(dnsConf, allSettings.DNS, logger, streamMerger, nonRootUsername, puid, pgid) wg.Add(1) // wait for unboundLooper.Restart or its ticker launched with RunRestartTicker go unboundLooper.Run(ctx, wg, signalDNSReady) publicIPLooper := publicip.NewLooper( - httpClient, logger, allSettings.PublicIP, uid, gid, os) + httpClient, logger, allSettings.PublicIP, puid, pgid, os) wg.Add(1) go publicIPLooper.Run(ctx, wg) wg.Add(1) diff --git a/internal/dns/conf.go b/internal/dns/conf.go index d9f51e9b..455a27cd 100644 --- a/internal/dns/conf.go +++ b/internal/dns/conf.go @@ -15,7 +15,7 @@ import ( ) func (c *configurator) MakeUnboundConf(ctx context.Context, settings settings.DNS, - username string, uid, gid int) (err error) { + username string, puid, pgid int) (err error) { c.logger.Info("generating Unbound configuration") lines, warnings := generateUnboundConf(ctx, settings, username, c.client, c.logger) for _, warning := range warnings { @@ -34,7 +34,7 @@ func (c *configurator) MakeUnboundConf(ctx context.Context, settings settings.DN return err } - if err := file.Chown(uid, gid); err != nil { + if err := file.Chown(puid, pgid); err != nil { _ = file.Close() return err } diff --git a/internal/dns/dns.go b/internal/dns/dns.go index 28f4a304..7fdd082b 100644 --- a/internal/dns/dns.go +++ b/internal/dns/dns.go @@ -13,9 +13,9 @@ import ( ) type Configurator interface { - DownloadRootHints(ctx context.Context, uid, gid int) error - DownloadRootKey(ctx context.Context, uid, gid int) error - MakeUnboundConf(ctx context.Context, settings settings.DNS, username string, uid, gid int) (err error) + DownloadRootHints(ctx context.Context, puid, pgid int) error + DownloadRootKey(ctx context.Context, puid, pgid int) error + MakeUnboundConf(ctx context.Context, settings settings.DNS, username string, puid, pgid int) (err error) UseDNSInternally(IP net.IP) UseDNSSystemWide(ip net.IP, keepNameserver bool) error Start(ctx context.Context, logLevel uint8) (stdout io.ReadCloser, waitFn func() error, err error) diff --git a/internal/dns/loop.go b/internal/dns/loop.go index fe2eefdf..ccc8f4b2 100644 --- a/internal/dns/loop.go +++ b/internal/dns/loop.go @@ -28,8 +28,8 @@ type looper struct { logger logging.Logger streamMerger command.StreamMerger username string - uid int - gid int + puid int + pgid int loopLock sync.Mutex start chan struct{} running chan models.LoopStatus @@ -41,7 +41,7 @@ type looper struct { } func NewLooper(conf Configurator, settings settings.DNS, logger logging.Logger, - streamMerger command.StreamMerger, username string, uid, gid int) Looper { + streamMerger command.StreamMerger, username string, puid, pgid int) Looper { return &looper{ state: state{ status: constants.Stopped, @@ -50,8 +50,8 @@ func NewLooper(conf Configurator, settings settings.DNS, logger logging.Logger, conf: conf, logger: logger.WithPrefix("dns over tls: "), username: username, - uid: uid, - gid: gid, + puid: puid, + pgid: pgid, streamMerger: streamMerger, start: make(chan struct{}), running: make(chan models.LoopStatus), @@ -287,14 +287,14 @@ func (l *looper) RunRestartTicker(ctx context.Context, wg *sync.WaitGroup) { } func (l *looper) updateFiles(ctx context.Context) (err error) { - if err := l.conf.DownloadRootHints(ctx, l.uid, l.gid); err != nil { + if err := l.conf.DownloadRootHints(ctx, l.puid, l.pgid); err != nil { return err } - if err := l.conf.DownloadRootKey(ctx, l.uid, l.gid); err != nil { + if err := l.conf.DownloadRootKey(ctx, l.puid, l.pgid); err != nil { return err } settings := l.GetSettings() - if err := l.conf.MakeUnboundConf(ctx, settings, l.username, l.uid, l.gid); err != nil { + if err := l.conf.MakeUnboundConf(ctx, settings, l.username, l.puid, l.pgid); err != nil { return err } return nil diff --git a/internal/dns/roots.go b/internal/dns/roots.go index f6a950fb..51455043 100644 --- a/internal/dns/roots.go +++ b/internal/dns/roots.go @@ -10,17 +10,17 @@ import ( "github.com/qdm12/gluetun/internal/constants" ) -func (c *configurator) DownloadRootHints(ctx context.Context, uid, gid int) error { +func (c *configurator) DownloadRootHints(ctx context.Context, puid, pgid int) error { return c.downloadAndSave(ctx, "root hints", - string(constants.NamedRootURL), string(constants.RootHints), uid, gid) + string(constants.NamedRootURL), string(constants.RootHints), puid, pgid) } -func (c *configurator) DownloadRootKey(ctx context.Context, uid, gid int) error { +func (c *configurator) DownloadRootKey(ctx context.Context, puid, pgid int) error { return c.downloadAndSave(ctx, "root key", - string(constants.RootKeyURL), string(constants.RootKey), uid, gid) + string(constants.RootKeyURL), string(constants.RootKey), puid, pgid) } -func (c *configurator) downloadAndSave(ctx context.Context, logName, url, filepath string, uid, gid int) error { +func (c *configurator) downloadAndSave(ctx context.Context, logName, url, filepath string, puid, pgid int) error { c.logger.Info("downloading %s from %s", logName, url) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { @@ -48,7 +48,7 @@ func (c *configurator) downloadAndSave(ctx context.Context, logName, url, filepa return err } - err = file.Chown(uid, gid) + err = file.Chown(puid, pgid) if err != nil { _ = file.Close() return err diff --git a/internal/openvpn/auth.go b/internal/openvpn/auth.go index 54ca4461..2ca267c9 100644 --- a/internal/openvpn/auth.go +++ b/internal/openvpn/auth.go @@ -9,7 +9,7 @@ import ( ) // WriteAuthFile writes the OpenVPN auth file to disk with the right permissions. -func (c *configurator) WriteAuthFile(user, password string, uid, gid int) error { +func (c *configurator) WriteAuthFile(user, password string, puid, pgid int) error { const filepath = string(constants.OpenVPNAuthConf) file, err := c.os.OpenFile(filepath, os.O_RDONLY, 0) @@ -27,7 +27,7 @@ func (c *configurator) WriteAuthFile(user, password string, uid, gid int) error _ = file.Close() return err } - err = file.Chown(uid, gid) + err = file.Chown(puid, pgid) if err != nil { _ = file.Close() return err @@ -59,7 +59,7 @@ func (c *configurator) WriteAuthFile(user, password string, uid, gid int) error _ = file.Close() return err } - err = file.Chown(uid, gid) + err = file.Chown(puid, pgid) if err != nil { _ = file.Close() return err diff --git a/internal/openvpn/loop.go b/internal/openvpn/loop.go index 86ae927f..4417ef16 100644 --- a/internal/openvpn/loop.go +++ b/internal/openvpn/loop.go @@ -35,8 +35,8 @@ type looper struct { state state // Fixed parameters username string - uid int - gid int + puid int + pgid int // Configurators conf Configurator fw firewall.Configurator @@ -56,7 +56,7 @@ type looper struct { } func NewLooper(settings settings.OpenVPN, - username string, uid, gid int, allServers models.AllServers, + username string, puid, pgid int, allServers models.AllServers, conf Configurator, fw firewall.Configurator, routing routing.Routing, logger logging.Logger, client *http.Client, openFile os.OpenFileFunc, streamMerger command.StreamMerger, cancel context.CancelFunc) Looper { @@ -67,8 +67,8 @@ func NewLooper(settings settings.OpenVPN, allServers: allServers, }, username: username, - uid: uid, - gid: gid, + puid: puid, + pgid: pgid, conf: conf, fw: fw, routing: routing, @@ -123,7 +123,7 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) { return } - if err := l.conf.WriteAuthFile(settings.User, settings.Password, l.uid, l.gid); err != nil { + if err := l.conf.WriteAuthFile(settings.User, settings.Password, l.puid, l.pgid); err != nil { l.logger.Error(err) l.cancel() return diff --git a/internal/openvpn/openvpn.go b/internal/openvpn/openvpn.go index a1a4551b..92bcbc27 100644 --- a/internal/openvpn/openvpn.go +++ b/internal/openvpn/openvpn.go @@ -12,7 +12,7 @@ import ( type Configurator interface { Version(ctx context.Context) (string, error) - WriteAuthFile(user, password string, uid, gid int) error + WriteAuthFile(user, password string, puid, pgid int) error CheckTUN() error CreateTUN() error Start(ctx context.Context) (stdout io.ReadCloser, waitFn func() error, err error) diff --git a/internal/params/params.go b/internal/params/params.go index 46ad9119..6adb7996 100644 --- a/internal/params/params.go +++ b/internal/params/params.go @@ -33,8 +33,8 @@ type Reader interface { GetDNSKeepNameserver() (on bool, err error) // System - GetUID() (uid int, err error) - GetGID() (gid int, err error) + GetPUID() (puid int, err error) + GetPGID() (pgid int, err error) GetTimezone() (timezone string, err error) GetPublicIPFilepath() (filepath models.Filepath, err error) diff --git a/internal/params/system.go b/internal/params/system.go index 6f5b60aa..9b98974d 100644 --- a/internal/params/system.go +++ b/internal/params/system.go @@ -4,14 +4,20 @@ import ( libparams "github.com/qdm12/golibs/params" ) -// GetUID obtains the user ID to use from the environment variable UID. -func (r *reader) GetUID() (uid int, err error) { - return r.envParams.GetEnvIntRange("UID", 0, 65535, libparams.Default("1000")) +// GetPUID obtains the user ID to use from the environment variable PUID +// with retro compatible variable UID. +func (r *reader) GetPUID() (ppuid int, err error) { + return r.envParams.GetEnvIntRange("PUID", 0, 65535, + libparams.Default("1000"), + libparams.RetroKeys([]string{"UID"}, r.onRetroActive)) } -// GetGID obtains the group ID to use from the environment variable GID. -func (r *reader) GetGID() (gid int, err error) { - return r.envParams.GetEnvIntRange("GID", 0, 65535, libparams.Default("1000")) +// GetGID obtains the group ID to use from the environment variable PGID +// with retro compatible variable PGID. +func (r *reader) GetPGID() (pgid int, err error) { + return r.envParams.GetEnvIntRange("PGID", 0, 65535, + libparams.Default("1000"), + libparams.RetroKeys([]string{"GID"}, r.onRetroActive)) } // GetTZ obtains the timezone from the environment variable TZ. diff --git a/internal/publicip/fs.go b/internal/publicip/fs.go index dbaa5b14..b2a60ccd 100644 --- a/internal/publicip/fs.go +++ b/internal/publicip/fs.go @@ -3,7 +3,7 @@ package publicip import "github.com/qdm12/gluetun/internal/os" func persistPublicIP(openFile os.OpenFileFunc, - filepath string, content string, uid, gid int) error { + filepath string, content string, puid, pgid int) error { file, err := openFile( filepath, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, @@ -18,7 +18,7 @@ func persistPublicIP(openFile os.OpenFileFunc, return err } - if err := file.Chown(uid, gid); err != nil { + if err := file.Chown(puid, pgid); err != nil { _ = file.Close() return err } diff --git a/internal/publicip/loop.go b/internal/publicip/loop.go index 339e2837..69caaf9d 100644 --- a/internal/publicip/loop.go +++ b/internal/publicip/loop.go @@ -31,8 +31,8 @@ type looper struct { logger logging.Logger os os.OS // Fixed settings - uid int - gid int + puid int + pgid int // Internal channels and locks loopLock sync.Mutex start chan struct{} @@ -46,7 +46,7 @@ type looper struct { } func NewLooper(client *http.Client, logger logging.Logger, - settings settings.PublicIP, uid, gid int, + settings settings.PublicIP, puid, pgid int, os os.OS) Looper { return &looper{ state: state{ @@ -57,8 +57,8 @@ func NewLooper(client *http.Client, logger logging.Logger, getter: NewIPGetter(client), logger: logger.WithPrefix("ip getter: "), os: os, - uid: uid, - gid: gid, + puid: puid, + pgid: pgid, start: make(chan struct{}), running: make(chan models.LoopStatus), stop: make(chan struct{}), @@ -144,7 +144,7 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) { l.state.setPublicIP(ip) l.logger.Info("Public IP address is %s", ip) filepath := string(l.state.settings.IPFilepath) - err := persistPublicIP(l.os.OpenFile, filepath, ip.String(), l.uid, l.gid) + err := persistPublicIP(l.os.OpenFile, filepath, ip.String(), l.puid, l.pgid) if err != nil { l.logger.Error(err) } diff --git a/internal/settings/system.go b/internal/settings/system.go index 3d51b16c..b18a3ff5 100644 --- a/internal/settings/system.go +++ b/internal/settings/system.go @@ -9,18 +9,18 @@ import ( // System contains settings to configure system related elements. type System struct { - UID int - GID int + PUID int + PGID int Timezone string } // GetSystemSettings obtains the System settings using the params functions. func GetSystemSettings(paramsReader params.Reader) (settings System, err error) { - settings.UID, err = paramsReader.GetUID() + settings.PUID, err = paramsReader.GetPUID() if err != nil { return settings, err } - settings.GID, err = paramsReader.GetGID() + settings.PGID, err = paramsReader.GetPGID() if err != nil { return settings, err } @@ -34,8 +34,8 @@ func GetSystemSettings(paramsReader params.Reader) (settings System, err error) func (s *System) String() string { settingsList := []string{ "System settings:", - fmt.Sprintf("User ID: %d", s.UID), - fmt.Sprintf("Group ID: %d", s.GID), + fmt.Sprintf("Process user ID: %d", s.PUID), + fmt.Sprintf("Process group ID: %d", s.PGID), fmt.Sprintf("Timezone: %s", s.Timezone), } return strings.Join(settingsList, "\n|--")