海运的博客

使用avahi配置mdns/dns-sd网络发现samba/ftp

发布时间:April 4, 2022 // 分类: // No Comments

配置avahi使用mdns/dns-sd零配置发现samba/smb共享存储:

1
apt install avahi-daemon
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat <<EOF > /etc/avahi/services/smb.service
<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
  <name replace-wildcards="yes">Samba</name>
  <service>
    <type>_smb._tcp</type>
    <host-name>smb.haiyun.me.local</host-name>
    <port>445</port> 
    <txt-record>path=/share</txt-record>
    <txt-record>u=guest</txt-record>
    <txt-record>p=pass</txt-record>
  </service>
</service-group>
EOF
echo '192.168.168.1 smb.haiyun.me.local' >> /etc/avahi/hosts

ftp服务器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat <<EOF > /etc/avahi/services/ftp.service
<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
  <name replace-wildcards="yes">FTP</name>
  <service>
    <type>_ftp._tcp</type>
    <host-name>ftp.haiyun.me.local</host-name>
    <port>21</port> 
    <txt-record>path=/share</txt-record>
    <txt-record>u=guest</txt-record>
    <txt-record>p=pass</txt-record>
  </service>
</service-group>
EOF
echo '192.168.168.2 ftp.haiyun.me.local' >> /etc/avahi/hosts

注意:
1.host-name可使用FQDN标准域名,但是smb有的客户端不识别。
2.avahi默认会为hosts内目标ip添加反查域名,所以当在/etc/avahi/hosts内添加多个域名指向同一ip时会出错:

1
Static host name smb.haiyun.me.local: avahi_server_add_address failure: Local name collision

可以使用avahi-publish手工发布域名且不添加ip反查域名:

1
avahi-publish -a -R smb.haiyun.me.local 168.168.168.1

也可以修改systemd service让avahi启动时自动启动avahi-publish:

1
2
3
4
5
6
7
apt install avahi-utils
cat <<EOF > /usr/local/bin/avahi-host.sh
#!/bin/bash
/usr/bin/avahi-publish -a -R smb.haiyun.me.local 168.168.168.1 > /dev/null 2>&1 &
EOF
chmod +x /usr/local/bin/avahi-host.sh
sed -i '/ExecStart/aExecStartPost=\/usr\/local\/bin\/avahi-host\.sh' /lib/systemd/system/avahi-daemon.service
1
2
3
4
systemctl daemon-reload
systemctl restart avahi-daemon.service
#手工修改添加ExecStartPost=/usr/local/bin/avahi-host.sh
#systemctl edit --full avahi-daemon.service

使用dig测试mdns/dns-sd:

1
2
3
4
5
6
7
dig -p 5353 @224.0.0.251 ftp.haiyun.me.local
dig -p 5353 @224.0.0.251 _smb._tcp.local ptr
dns-sd -B _services._dns-sd._udp
dns-sd -B _smb._tcp
dns-sd -Z _smb._tcp
dns-sd -Q smb.haiyun.me.local
dns-sd -Q smb.haiyun.me.local aaaa

当同一ip有多个服务时也可使用基于golang dnssd的mdns/dns-sd服务:

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
package main
 
import (
        "context"
        "encoding/json"
        "fmt"
        "github.com/brutella/dnssd"
        "net"
        "os"
        "os/signal"
        "time"
)
 
type service struct {
        Name   string
        Type   string
        Domain string
        Host   string
        Ips    []string
        Port   int
        Text   map[string]interface{}
}
 
type config struct {
        Service []service
}
 
func main() {
        cfg_str, err := os.ReadFile("config.json")
        if err != nil {
                fmt.Println("load config file error:", err)
                os.Exit(1)
        }
        var cfg config
        err = json.Unmarshal(cfg_str, &cfg)
        if err != nil {
                fmt.Println("decode json err:", err)
                os.Exit(1)
        }
 
        if resp, err := dnssd.NewResponder(); err != nil {
                fmt.Println(err)
        } else {
                for _, v := range cfg.Service {
                        var ips []net.IP
                        for _, ip := range v.Ips {
                                ips = append(ips, net.ParseIP(ip))
                        }
                        text := make(map[string]string)
                        for key, value := range v.Text {
                                text[key] = fmt.Sprintf("%v", value)
                        }
                        sd_cfg := dnssd.Config{
                                Name:   v.Name,
                                Type:   v.Type,
                                Domain: v.Domain,
                                Host:   v.Host,
                                IPs:    ips,
                                Port:   v.Port,
                                Text:   text,
                        }
 
                        srv, err := dnssd.NewService(sd_cfg)
                        if err != nil {
                                fmt.Println(err)
                        }
                        go func() {
                                time.Sleep(1 * time.Second)
                                handle, err := resp.Add(srv)
                                if err != nil {
                                        fmt.Println(err)
                                } else {
                                        fmt.Printf("%s  Got a reply for service %s: Name now registered and active\n", time.Now().Format("2006-01-02 15:04:05"), handle.Service().ServiceInstanceName())
                                }
                        }()
                }
 
                ctx, cancel := context.WithCancel(context.Background())
                defer cancel()
                go func() {
                        stop := make(chan os.Signal, 1)
                        signal.Notify(stop, os.Interrupt)
 
                        select {
                        case <-stop:
                                cancel()
                        }
                }()
 
                err = resp.Respond(ctx)
                if err != nil {
                        fmt.Println(err)
                }
        }
}

配置文件保存到同目录config.json:

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
{
  "service":[
    {
      "name":"Samba",
      "type":"_smb._tcp",
      "domain":"local",
      "host":"smb.haiyun.me",
      "ips":[
        "10.0.0.1",
        "fdb2:808c:d0ef:0:20c:29ff:fe7c:264d"
      ],
      "port":445,
      "text":{
        "u":"user",
        "p":"pass",
        "path":"/share"
      }
    },
    {
      "name":"Ftp",
      "type":"_ftp._tcp",
      "domain":"local",
      "host":"ftp.haiyun.me",
      "ips":[
        "10.0.0.1",
        "fdb2:808c:d0ef:0:20c:29ff:fe7c:264d"
      ],
      "port":21,
      "text":{
        "u":"user",
        "p":"pass",
        "path":"/share"
      }
    }
  ]
}

更多服务类型及参数见:
http://www.dns-sd.org/ServiceTypes.html
本地多个不同网段mdns中继:
https://www.haiyun.me/archives/1439.html
参考:
https://github.com/brutella/dnssd
https://kodi.wiki/view/Avahi_Zeroconf
https://linux.die.net/man/5/avahi.service
https://github.com/lathiat/avahi/issues/40
https://pi3g.com/2019/04/10/avahi-how-to-assign-several-local-names-to-same-ip/

标签:golang, smb, mdns, dns-sd, nas

评论已关闭

分类
最新文章
最近回复
  • opnfense: 谢谢博主!!!解决问题了!!!我之前一直以为内置的odhcp6就是唯一管理ipv6的方式
  • liyk: 这个方法获取的IPv6大概20分钟之后就会失效,默认路由先消失,然后Global IPV6再消失
  • 海运: 不好意思,没有。
  • zongboa: 您好,請問一下有immortalwrt設定guest Wi-Fi的GUI教學嗎?感謝您。
  • 海运: 恩山有很多。
  • swsend: 大佬可以分享一下固件吗,谢谢。
  • Jimmy: 方法一 nghtp3步骤需要改成如下才能编译成功: git clone https://git...
  • 海运: 地址格式和udpxy一样,udpxy和msd_lite能用这个就能用。
  • 1: 怎么用 编译后的程序在家里路由器内任意一台设备上运行就可以吗?比如笔记本电脑 m参数是笔记本的...
  • 孤狼: ups_status_set: seems that UPS [BK650M2-CH] is ...
StatCounter - Free Web Tracker and Counter