potpro (ぽとぷろ)
Full-stuck engineer(Not Full-stack)
JS/PHP/Go/Docker/Nginxなど。技術または趣味寄りの発信ブログです。
全 85 記事telnet接続可能なホームページをGoで作って公開してみた
telnet接続可能なホームページをGoで作って公開してみた
すぐに試してみたい人はtelnet potproject.net
または telnet potp.ro
で接続できます!
はい、また流行りに乗った記事です。
パッと作れないかなと思って実際に作ってみると結構面白く、Blueskyの方からアクセスも結構あったので記事にしました。
概要
9/4、このようなものが公開されて話題を呼びました。
社団法人の電子公告が「Telnet」で行われる珍事発生、早速「Tera Term」で読んでみる
電子公告が「Telnet」を使って行われているというものです。Telnetはhttpよりもはるか昔から存在する通信プロトコルですね。
実はhttp/httpsじゃないといけないと決まっているわけではないからライブラリは何でもよいとのこと。
ftpとかsshでもいいんだろうか?と思いつつ、実際にtelnetで接続してみると、1文字ずつ真心を込めたTCP Socket送信が行われました。
パフォーマンスを日々考えてWebを改修をしているような現代ではこの速度がとても心地よく感じますね・・・。
自分もインターネットに生きるものとして、telnetを使ってホームページ(と言うのか?)を作ってみたい!!と思ったので、さくっと実装してみました。
実装方法
今回は、go-telnetを使いました。
Go言語にこんなライブラリがあるんですね。これがnet/httpと似たように設計になっていて、中々に使いやすいです。
ちなみに自分はtelnetの知識はほぼ皆無です。TCPの双方向通信であるということくらい。使ったことも多分2,3回しか無いですね。
今回は電子公告と同じように、一方的にデータを送り付けるだけの仕様とします。この仕様であれば、平文で送信してもセキュリティ上の問題は起きづらい・・・はず。
より詳しくセキュリティに関しては一般社団法人サイバー技術・インターネット自由研究会の電子公告をご覧ください。全部読むのに10分くらいかかります。
違う部分としては文字コードにShift-JISではなくUTF-8を使ってます。理由は・・・察してください。(単にすごくめんどくさかったというのもある)。改行コードはlfなので、Tera Termのデフォルト(cr)だとうまく表示できません。変更してください。
うちのサイトはUnix系のtelnetコマンドでの表示に最適化されています。Shift-JISしかサポートされていないレガシー端末をお持ちの方はすみません。
今のところWindows/Linuxでのtelnetコマンドやncコマンドで正常に表示を確認しています。
但し環境依存文字を使用しているため、アスキーアートは崩れやすいです。teratermだと崩れちゃう。でもどうしても入れたかったんや・・・文字だけで表現するとなると欲しいよね。
コード
コードとしてはこんな感じです。文字だけということもあり、簡単に作れました。
package main
import (
"context"
"fmt"
"io/ioutil"
"os"
"os/signal"
"strconv"
"syscall"
"time"
telnet "github.com/reiver/go-telnet"
)
var counter int = 0
func main() {
counter = loadCounter()
var handler telnet.Handler = MainHandler{}
fmt.Println("start server")
go func() {
err := telnet.ListenAndServe(":23", handler)
if nil != err {
panic(err)
}
}()
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, os.Interrupt, os.Kill)
defer stop()
<-ctx.Done()
saveCounter(counter)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
}
func loadCounter() int {
// 略
}
func saveCounter(counter int) {
// 略
}
type MainHandler struct{}
func (handler MainHandler) ServeTELNET(ctx telnet.Context, w telnet.Writer, r telnet.Reader) {
counter++
str := `
----------
You must not use Shift_JIS encoding to view this page!!!
Please use UTF-8 encoding.
----------
□□□□ あなたは ` + fmt.Sprintf("%05d", counter) + ` 人目の訪問者です □□□□
----------
∧__∧
( ´・ω・) _ _ _ _
|ノ| ノ)ノ)|ゝ | | (_) | | | |
メ_ > ❙ レノ_ | |_ _ __ _ __ ___ _ ___ ___| |_ _ __ ___| |_
| '_ \ / _ \| __| '_ \| '__/ _ \| |/ _ \/ __| __| | '_ \ / _ \ __|
| |_) | (_) | |_| |_) | | | (_) | | __/ (__| |_ _ | | | | __/ |_
| .__/ \___/ \__| .__/|_| \___/| |\___|\___|\__| (_) |_| |_|\___|\__|
| | | | _/ |
|_| |_| |__/
# Profile
Name: potpro (ぽとぷろ)
Blog: blog.potproject.net (https://blog.potproject.net)
Github: @potproject (https://github.com/potproject)
X(Twitter): @potpro (https://twitter.com/potpro)
Mastodon: https://mastodon.potproject.net/@potpro
Bluesky: https://bsky.app/profile/potp.ro
----------
`
for _, c := range str {
w.Write([]byte(string(c)))
time.Sleep(50 * time.Millisecond)
}
}
こだわりポイントとして、同様に1文字ずつ転送することと懐かしのアクセスカウンターを雑に実 装してみました。 キリ番を踏んだ方は是非自分までご連絡ください。
現代のマシンと通信回線は処理も速度も早すぎて、文字が一瞬で表示されてしまい趣がありません。
Sleepを入れることにより、1秒に20文字までしか処理できないようにわざと遅くしています。
for _, c := range str {
w.Write([]byte(string(c)))
time.Sleep(50 * time.Millisecond)
}
}
というよりコードを見てもらえばわかるように、ここが送信部分のメイン処理です。 確かにめちゃくちゃシンプルですね。脆弱性が入り込む余地は無さそう。
コードはgithubに公開しています。
このコードは日本ではなくマサチューセッツ工科大学が定めたMITライセンスで公開しているので、誰でも制限なく使っていただければと思います。
文章だけ変えて自分もtelnetでホームページを作りたいという方が居れば是非お使いください。いるかはわからないですか。
(雑な部分は後で直すかも)
所感
やった後に気づきましたが、これやってることパソコン通信だ!?
もう少し凝った作りにすると双方向で対話的な通信も出来るので、そこまでやると草の根BBSになってしまいますね。
この時代の人間では無いので、気づきませんでしたが・・・インターネットは、基礎技術の部分ってのは変わらないんだなと感じました。
最近はもはや何でもできるレベルにリッチなインターネットですが、たまにはこういうのに触れるのも良いと思いました。終わり。