golang で URL を結合する
golang で URL を結合する
- url.Parse と path.Join を使う
- path.Join だけだと正しく結合できない場合がある1
- 実行結果の
https:/golang.org/pkg/net/url
のようにスラッシュが削除される
- 実行結果の
サンプルコード
package main import ( "fmt" "net/url" "path" ) const ( srcURL = "https://golang.org/pkg/" path1 = "net" path2 = "url" ) func main() { fmt.Printf("path.Join だけで結合: %s\n", path.Join(srcURL, path1, path2)) u, err := url.Parse(srcURL) if err != nil { panic(err) } u.Path = path.Join(u.Path, path1, path2) fmt.Printf("url.Parse と path.Join で結合: %s\n", u) }
実行結果
path.Join だけで結合: https:/golang.org/pkg/net/url url.Parse と path.Join で結合: https://golang.org/pkg/net/url
参考にさせていただいたサイト
golang で UUID を使う
golang で UUID を使う
- ライブラリは https://github.com/google/uuid を使います
- GoDoc: https://pkg.go.dev/github.com/google/uuid
サンプルコード
package main import ( "fmt" "github.com/google/uuid" ) func main() { // uuid.NewRandom() はランダムなバージョン 4 の UUID を返す id1, err := uuid.NewRandom() if err != nil { panic(err) } fmt.Printf("id1, %s, %s, %s\n", id1.Variant(), id1.Version(), id1) // uuid.New() はランダムな UUID を返すか、パニックを起こす // uuid.New() は uuid.Must(uuid.NewRandom()) と等価 id2 := uuid.New() fmt.Printf("id2, %s, %s, %s\n", id2.Variant(), id2.Version(), id2) }
サンプルコード実行結果
id1, RFC4122, VERSION_4, ce33574c-5716-4c02-b833-2651b2a90a84 id2, RFC4122, VERSION_4, 5775e7ad-ee61-48f9-9e35-fd7d890b40f5
Raspberry Pi 4 でローカル DNS サーバを立てる
Raspberry Pi 4 と BIND 9 で自宅ネットワーク用の DNS サーバを立てました。
ラズパイに sv.homenetwork
というドメイン名を付けてみます。
ラズパイ情報
$ cat /etc/os-release PRETTY_NAME="Raspbian GNU/Linux 10 (buster)" NAME="Raspbian GNU/Linux" VERSION_ID="10" VERSION="10 (buster)" VERSION_CODENAME=buster ID=raspbian ID_LIKE=debian HOME_URL="http://www.raspbian.org/" SUPPORT_URL="http://www.raspbian.org/RaspbianForums" BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
ラズパイに BIND 9 をインストールする
$ sudo apt install bind9 $ named -v BIND 9.11.5-P4-5.1+deb10u2-Raspbian (Extended Support Version)
BIND 9 を設定する
192.168.1.0/24
を homenetwork
というゾーンにします。
ラズパイには sv.homenetwork
というドメイン名を付けてみます。
/etc/bind/named.conf
このファイルから /etc/bind/named.conf.options
と
/etc/bind/named.conf.local
をインクルードするみたいです。
このファイルはデフォルトのままで、設定変更しませんでした。
$ cat /etc/bind/named.conf // This is the primary configuration file for the BIND DNS server named. // // Please read /usr/share/doc/bind9/README.Debian.gz for information on the // structure of BIND configuration files in Debian, *BEFORE* you customize // this configuration file. // // If you are just adding zones, please do that in /etc/bind/named.conf.local include "/etc/bind/named.conf.options"; include "/etc/bind/named.conf.local"; include "/etc/bind/named.conf.default-zones";
/etc/bind/named.conf.options
このファイルに DNSサーバの設定を書いていきます。
$ cat /etc/bind/named.conf.options options { // サーバの作業ディレクトリ // このディレクトに後述するゾーンファイルを置くみたいです directory "/var/cache/bind"; // 自身が属するネットワークからのクエリのみ許可する allow-query { localnets; }; // ゾーン転送するセカンダリサーバは存在しないので無効にする allow-transfer { none; }; // 自身で解決できない問い合わせを別のフルリゾルバに転送する // 自宅ルータの 192.168.1.1 がフォワーダとして動作し // プロバイダのフルリゾルバに転送してくれます forwarders { 192.168.1.1; }; // フォワーダから回答が得られない場合はエラーとなる forward only; // DNSSEC を無効 dnssec-validation no; // IPv6 のクエリに対応する listen-on-v6 { any; }; };
/etc/bind/named.conf.local
このファイルでゾーンファイルを指定するみたいです。
$ cat /etc/bind/named.conf.local zone "homenetwork" IN { // 権威サーバの情報 // セカンダリサーバ(slave)は存在しないので // プライマリサーバ(master)とします type master; file "homenetwork.zone"; }; zone "1.168.192.in-addr.arpa" IN { type master; file "homenetwork.rev"; };
/var/cache/bind/homenetwork.zone
正引き用のゾーンデータを記述するゾーンファイルです。
refresh, retry, expire はセカンダリサーバが存在しないので、
使われないような気がします。
$ cat /var/cache/bind/homenetwork.zone $TTL 3600 @ IN SOA sv.homenetwork. root.homenetwork. ( 2015123105 ; serial 3H ; refresh 15M ; retry 1W ; expire 1H ) ; minimum IN NS sv sv IN A 192.168.1.10
/var/cache/bind/homenetwork.rev
逆引き用のゾーンデータを記述するゾーンファイルです。
$ cat /var/cache/bind/homenetwork.rev $TTL 3600 @ IN SOA sv.homenetwork. root.homenetwork. ( 2015123105 ; serial 3H ; refresh 15M ; retry 1W ; expire 1H ) ; minimum IN NS sv.homenetwork. 10 IN PTR sv.homenetwork.
設定ファイルのチェックを行う
$ sudo named-checkconf $ sudo named-checkzone 1.168.192.in-addr.arpa /var/cache/bind/homenetwork.rev zone 1.168.192.in-addr.arpa/IN: loaded serial 2015123105 OK $ sudo named-checkzone homenetwork /var/cache/bind/homenetwork.zone zone homenetwork/IN: loaded serial 2015123105 OK
ラズパイが問い合わせる DNS サーバを自分自身にする
自宅ネットワークでは DHCP を使用しているので
ラズパイの /etc/dhcpcd.conf
に以下を追記します。
static domain_name_servers=127.0.0.1 static domain_name=homenetwork
BIND 9 の再起動
BIND 9 を再起動して、ステータスに異常がないか確認します。
$ sudo systemctl restart bind9 $ sudo systemctl status bind9
DHCP サーバが配布する DNS サーバのアドレスをラズパイのアドレスに変更する
DHCP を使用している場合は DHCP サーバ の設定を変更します。
正引きテスト
作業用 PC からテストします。まずは直接 192.168.1.10 に問い合わせてみます。
status: NOERROR
で flags
に aa
があります。
大丈夫そうです。
$ dig @192.168.1.10 sv.homenetwork ; <<>> DiG 9.16.1-Ubuntu <<>> @192.168.1.10 sv.homenetwork ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61550 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1 ... ;; ANSWER SECTION: sv.homenetwork. 3600 IN A 192.168.1.10 ;; AUTHORITY SECTION: homenetwork. 3600 IN NS sv.homenetwork. ...
外部のドメインも試してみます。今度は flags
に ra
があります。
大丈夫そうです。
$ dig @192.168.1.10 www.google.com ; <<>> DiG 9.16.1-Ubuntu <<>> @192.168.1.10 www.google.com ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63049 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ... ;; ANSWER SECTION: www.google.com. 42 IN A 172.217.24.132 ...
次に systemd-resolved を経由して問い合わせてみます。
こっちも大丈夫そうです。
$ dig sv.homenetwork ; <<>> DiG 9.16.1-Ubuntu <<>> sv.homenetwork ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30774 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ... ;; ANSWER SECTION: sv.homenetwork. 3038 IN A 192.168.1.10 ...
逆引きテスト
dig @192.168.1.10 -x 192.168.1.10
と dig -x 192.168.1.10
を試して、
大丈夫なことを確認しました。
systemd-resolved 経由の問い合わせがうまくいかないとき
systemd-resolve --status
してCurrent DNS Server
を確認するsystemctl restart systemd-resolved
で systemd-resolved を再起動してみる
参考にさせていただいたサイト
Raspberry Pi 4 のセットアップ
ラズパイ4スターターキット 4GB版 を秋月電子で購入しました。
行った設定などを書いておきます。
OS 情報
ラズパイ4スターターキット 4GB版
には Raspbian インストール済 microSD が付属してます。
そのため OS は付属の Raspbian を使うことにしました。ラズパイに microSD を挿すだけで OK です
$ cat /etc/os-release PRETTY_NAME="Raspbian GNU/Linux 10 (buster)" NAME="Raspbian GNU/Linux" VERSION_ID="10" VERSION="10 (buster)" VERSION_CODENAME=buster ID=raspbian ID_LIKE=debian HOME_URL="http://www.raspbian.org/" SUPPORT_URL="http://www.raspbian.org/RaspbianForums" BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
OS の GUI を無効化する
GUI は使わないので無効にします。
sudo raspi-config
を実行します1 System Options
>S5 Boot / Auto Login
>B1 Console
またはB2 Console Autologin
を選択して、ラズパイを再起動します- 私は
B1 Console
を選択しました
- 私は
Wi-Fi を無効化する
有線で接続するので Wi-Fi を無効にします。
/etc/rc.local
にiwconfig wlan0 txpower off
を追記して、再起動します
起動中に LED を点滅させる
起動してるのか分かりにくいので LED を点滅させます。
/boot/config.txt
にdtparam=act_led_trigger=heartbeat
を追記して、再起動しますact_led_trigger
で緑色 LED 、pwr_led_trigger
で赤色 LED が点滅します
ブラウザからラズパイを管理できるようにする
Cockpit をインストールすると、ブラウザからラズパイの状態確認やシャットダウン、再起動が行えます。
Cockpit インストール
$ sudo apt install dirmngr $ sudo apt install cockpit
Cockpit で HTTPS を無効化する
/etc/cockpit/cockpit.conf
に AllowUnencrypted = true
を設定します。
$ cat /etc/cockpit/cockpit.conf [WebService] AllowUnencrypted = true
ブラウザからログインする
http://ラズパイの IP アドレス:9090
にアクセスします
参考にさせていただいたサイト
golang でシグナルを扱う
golang でシグナルを扱う
- Go でシグナルを扱うには
singal.Notify
を使う - 以下のサンプルコードでは
SIGINT = ^C
を受信するとアプリケーションが停止する sigC := make(chan os.Signal, 1)
のように必ずバッファありチャネルが必要- os.Interrupt と os.Kill の2つはすべての OS で使えることが保証されている
package main import ( "log" "os" "os/signal" "sync" "time" ) func main() { // 受信するシグナル // Interrupt Signal = syscall.SIGINT sigs := []os.Signal{os.Interrupt} // 必ずバッファありチャネルが必要 // https://budougumi0617.github.io/2020/09/06/why_signal_notify_want_buffered_channel/ sigC := make(chan os.Signal, 1) signal.Notify(sigC, sigs...) var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() for { select { case <-time.After(2 * time.Second): log.Println("waiting...") case sig := <-sigC: log.Println("got signal", sig) return } } }() wg.Wait() }
参考サイト
sed で置換する
実行例
- 名前が チ で終わる犬に忠犬をつける
$ cat sample.xml <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <root> <dog name="ソフィア" age="7" /> <dog name="ポチ" age="5" /> <dog name="コロ" age="10" /> <dog name="ハチ" age="5" /> </root> $ sed -i -E 's/([ア-ン]+チ)/忠犬\1/g' sample.xml $ cat sample.xml <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <root> <dog name="ソフィア" age="7" /> <dog name="忠犬ポチ" age="5" /> <dog name="コロ" age="10" /> <dog name="忠犬ハチ" age="5" /> </root>
コマンド説明
sed -i -E 's/([ア-ン]+チ)/忠犬\1/g' sample.xml
-i
で置換した結果を元ファイルに上書きする-E
拡張正規表現を使用する- 後方参照は
\番号
で行う。キャプチャには()
を使用する