Skip to content

Instantly share code, notes, and snippets.

@private-yusuke
Created December 18, 2022 10:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save private-yusuke/d1bc5f3edaf720eb92747f305824f9d6 to your computer and use it in GitHub Desktop.
Save private-yusuke/d1bc5f3edaf720eb92747f305824f9d6 to your computer and use it in GitHub Desktop.
「2^64 個のグローバル IPv6 アドレスを用いたクイズを作ってみよう」のサーバーで動くプログラムのソースコード
package main
import (
"encoding/binary"
"encoding/json"
"fmt"
"io"
"log"
"net"
"net/http"
)
const MONEY uint64 = 0x2525_beef_4649_babe
type GetResponse struct {
Result int `json:"result"`
Comment string `json:"comment"`
}
func getRequestedV6Host(r *http.Request) (net.IP, error) {
host, _, err := net.SplitHostPort(r.Host)
if err != nil {
return nil, err
}
ip := net.ParseIP(host)
if ip.To16() == nil {
return nil, fmt.Errorf("invalid IPv6 address: %s", host)
}
return ip.To16(), nil
}
func v6OnlyMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ip, err := getRequestedV6Host(r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// If the client is accessing to this server by specifying an IPv4 address,
// return a 400
if ip == nil {
http.Error(w, "IPv4 not allowed", http.StatusBadRequest)
return
}
next.ServeHTTP(w, r)
})
}
func getIndex(w http.ResponseWriter, r *http.Request) {
const instruction = `You can make requests to: /host, /challenge
`
io.WriteString(w, instruction)
}
func getHost(w http.ResponseWriter, r *http.Request) {
host, err := getRequestedV6Host(r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
io.WriteString(w, host.String())
}
func getChallenge(w http.ResponseWriter, r *http.Request) {
var response GetResponse
toMoney := func(r *http.Request) (uint64, error) {
ip, err := getRequestedV6Host(r)
if err != nil {
return 0, err
}
money := binary.BigEndian.Uint64(ip[8:])
return money, nil
}
money, err := toMoney(r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
if money > MONEY {
response.Result = 1
response.Comment = "Too rich to be true (The answer is smaller than the value you specified)"
} else if money == MONEY {
response.Result = 0
response.Comment = "Congratulations!!!! (The answer is the same as the value you specified)"
} else {
response.Result = -1
response.Comment = "Too poor to be true (The answer is greater than the value you specified)"
}
json.NewEncoder(w).Encode(response)
}
func main() {
http.Handle("/", v6OnlyMiddleware(http.HandlerFunc(getIndex)))
http.Handle("/host", v6OnlyMiddleware(http.HandlerFunc(getHost)))
http.Handle("/challenge", v6OnlyMiddleware(http.HandlerFunc(getChallenge)))
log.Fatal(http.ListenAndServe(":8080", nil))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment