@@ -36,7 +36,7 @@ type UIConfig struct {
3636
3737type ApiConfig struct {
3838 Enabled bool
39- Listen string
39+ Listens [] string // one entry per bind address, always includes 127.0.0.1
4040 Port int
4141
4242 UI * UIConfig
@@ -88,10 +88,11 @@ func parseLogLevel(levelStr string) logger.Level {
8888 }
8989}
9090
91- // resolveBindToIP convertit bind (interface name ou "all") en IP pour l'API
92- func resolveBindToIP (bind string ) (string , error ) {
93- if bind == "all" {
94- return "0.0.0.0" , nil
91+ // resolveIfaceToIP returns the IPv4 address of a single named interface.
92+ // "lo" resolves to "127.0.0.1" without querying the OS interface list.
93+ func resolveIfaceToIP (bind string ) (string , error ) {
94+ if bind == "lo" {
95+ return "127.0.0.1" , nil
9596 }
9697
9798 iface , err := net .InterfaceByName (bind )
@@ -115,21 +116,63 @@ func resolveBindToIP(bind string) (string, error) {
115116 return "" , fmt .Errorf ("no IPv4 on interface %s" , bind )
116117}
117118
118- // getZeroconfInterfaces retourne les interfaces pour zeroconf
119- func getZeroconfInterfaces (bind string ) []net.Interface {
120- if bind == "all" {
121- return getAllActiveNonLoopback ()
119+ // resolveBindsToListens converts a list of bind names to host:port listen addresses.
120+ // "all" expands to 0.0.0.0 (which covers loopback too).
121+ // Otherwise 127.0.0.1 is always prepended if not already present.
122+ func resolveBindsToListens (binds []string , port string ) ([]string , error ) {
123+ for _ , b := range binds {
124+ if b == "all" {
125+ return []string {net .JoinHostPort ("0.0.0.0" , port )}, nil
126+ }
122127 }
123128
124- iface , err := net .InterfaceByName (bind )
125- if err != nil {
126- logger .Warn ("[config] interface %q not found: %v" , bind , err )
127- return nil
129+ seen := map [string ]bool {}
130+ var addrs []string
131+
132+ for _ , bind := range binds {
133+ ip , err := resolveIfaceToIP (bind )
134+ if err != nil {
135+ return nil , err
136+ }
137+ addr := net .JoinHostPort (ip , port )
138+ if ! seen [addr ] {
139+ seen [addr ] = true
140+ addrs = append (addrs , addr )
141+ }
128142 }
129- if iface .Flags & net .FlagUp == 0 || iface .Flags & net .FlagLoopback != 0 {
130- return nil
143+
144+ loopback := net .JoinHostPort ("127.0.0.1" , port )
145+ if ! seen [loopback ] {
146+ addrs = append ([]string {loopback }, addrs ... )
147+ }
148+
149+ return addrs , nil
150+ }
151+
152+ // getZeroconfInterfaces returns the network interfaces on which mDNS should be announced.
153+ func getZeroconfInterfaces (binds []string ) []net.Interface {
154+ for _ , b := range binds {
155+ if b == "all" {
156+ return getAllActiveNonLoopback ()
157+ }
131158 }
132- return []net.Interface {* iface }
159+
160+ var result []net.Interface
161+ for _ , bind := range binds {
162+ if bind == "lo" {
163+ continue
164+ }
165+ iface , err := net .InterfaceByName (bind )
166+ if err != nil {
167+ logger .Warn ("[config] interface %q not found: %v" , bind , err )
168+ continue
169+ }
170+ if iface .Flags & net .FlagUp == 0 || iface .Flags & net .FlagLoopback != 0 {
171+ continue
172+ }
173+ result = append (result , * iface )
174+ }
175+ return result
133176}
134177
135178// getAllActiveNonLoopback retourne toutes interfaces UP sauf loopback
@@ -229,8 +272,11 @@ func New(cfgFile *string) (*Config, error) {
229272 if port <= 0 || port > 65535 {
230273 return nil , fmt .Errorf ("invalid port: %d" , port )
231274 }
232- bind := viper .GetString ("bind" )
233- listenIP , err := resolveBindToIP (bind )
275+
276+ // bind accepts a single interface name or a list: "enp2s0", ["enp2s0","wlan0"], "all"
277+ binds := viper .GetStringSlice ("bind" )
278+ portStr := strconv .Itoa (port )
279+ listens , err := resolveBindsToListens (binds , portStr )
234280 if err != nil {
235281 return nil , err
236282 }
@@ -241,7 +287,7 @@ func New(cfgFile *string) (*Config, error) {
241287
242288 apiCfg := ApiConfig {
243289 Enabled : viper .GetBool ("api.enabled" ),
244- Listen : net . JoinHostPort ( listenIP , strconv . Itoa ( port )) ,
290+ Listens : listens ,
245291 Port : port ,
246292 UI : & uiCfg ,
247293 }
@@ -274,7 +320,7 @@ func New(cfgFile *string) (*Config, error) {
274320 Timeout : mprisTimeout ,
275321 }
276322
277- interfaces := getZeroconfInterfaces (bind )
323+ interfaces := getZeroconfInterfaces (binds )
278324 zerocfg := ZeroConfig {
279325 Enabled : viper .GetBool ("zeroconf.enabled" ),
280326 InstanceName : AppName ,
0 commit comments