Created
December 18, 2022 10:05
-
-
Save private-yusuke/d1bc5f3edaf720eb92747f305824f9d6 to your computer and use it in GitHub Desktop.
「2^64 個のグローバル IPv6 アドレスを用いたクイズを作ってみよう」のサーバーで動くプログラムのソースコード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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