Files
ipv6calculator/main.go
jbergner dd258426ca
All checks were successful
release-tag / release-image (push) Successful in 1m52s
Fix und Anpassungen für DNS und Gateway
2025-05-09 09:02:22 +02:00

215 lines
6.5 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// A small Go webserver that converts an IPv4 address into an IPv6 address
// inside a userdefined /96 ULA prefix and outputs Windows 11ready fields.
//
// Environment variables (all optional):
//
// ULA_PREFIX  /96 prefix to embed into, default "fdcb:7de3:a12a:0::"
// FORM_DEFAULT_IP - legt das Form Placeholder IP Feld fest (default: 172.16.0.0)
// DNS1  preferred DNS IPv6 address (default: <prefix with 1::53>)
// DNS2  alternate DNS IPv6 address (default: <prefix with 1::54>)
//
// Build & run:
//
// export ULA_PREFIX="fde5:1234:abcd:0::"
// export DNS1="fde5:1234:abcd:1::53" # optional
// export DNS2="fde5:1234:abcd:1::54" # optional
// go run main.go
//
// Open http://localhost:8080 in a browser.
package main
import (
"fmt"
"html/template"
"log"
"net"
"net/http"
"os"
"strings"
)
const (
listenAddr = ":8080"
defaultPrefix = "fd09:cafe:affe:4010::" // fallback /96
prefixLen = 96 // fixed /96 mapping
defaultIP = "172.16.0.0"
)
var (
ulaPrefix string // effective /96 prefix (always ends with ::)
dns1 string // preferred DNS
dns2 string // alternate DNS
pageIP string
pageTemplate *template.Template // compiled HTML template
)
// viewData is passed into the template.
type viewData struct {
IPv4 string
IPv6 string
Gateway string
DNS1 string
DNS2 string
Error string
HaveResult bool
}
func main() {
initConfigAndTemplate()
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
renderPage(w, viewData{})
})
http.HandleFunc("/convert", func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
renderPage(w, viewData{Error: "Ungültiges Formular"})
return
}
ipv4Str := r.FormValue("ipv4")
ipv6, err := embedIPv4(ipv4Str)
data := viewData{IPv4: ipv4Str}
if err != nil {
data.Error = err.Error()
} else {
data.HaveResult = true
data.IPv6 = ipv6
data.Gateway = ulaPrefix + "1" // router IP = <prefix>::1
data.DNS1 = dns1
data.DNS2 = dns2
}
renderPage(w, data)
})
log.Printf("Server läuft auf http://localhost%s (Präfix %s, DNS1 %s, DNS2 %s)", listenAddr, ulaPrefix, dns1, dns2)
log.Fatal(http.ListenAndServe(listenAddr, nil))
}
// initConfigAndTemplate reads env vars and prepares HTML template.
func initConfigAndTemplate() {
// ---- ULA prefix -------------------------------------------------------
ulaPrefix = os.Getenv("ULA_PREFIX")
if ulaPrefix == "" {
ulaPrefix = defaultPrefix
}
pageIP = os.Getenv("FORM_DEFAULT_IP")
if pageIP == "" {
pageIP = defaultIP
}
// ensure trailing :: so we can simply append hex words
if !strings.HasSuffix(ulaPrefix, "::") {
if strings.HasSuffix(ulaPrefix, ":") {
ulaPrefix += ":"
} else {
ulaPrefix += "::"
}
}
// ---- DNS addresses ----------------------------------------------------
dns1 = os.Getenv("DNS1")
dns2 = os.Getenv("DNS2")
// default DNS: change subnet 0 → 1 and append ::53 / ::54
if dns1 == "" {
dns1 = strings.Replace(ulaPrefix, "::", "::53", 1)
}
if dns2 == "" {
dns2 = strings.Replace(ulaPrefix, "::", "::54", 1)
}
// ---- HTML template ----------------------------------------------------
html := fmt.Sprintf(`<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8" />
<title>IPv4  IPv6Mapper</title>
<style>
body{font-family:system-ui,sans-serif;margin:2rem;max-width:46rem}
form{display:flex;gap:.5rem;flex-wrap:wrap}
input[type=text],input[readonly]{padding:.4rem;font-size:1rem;border:1px solid #ccc;border-radius:4px;flex:1}
button{padding:.5rem 1rem;font-size:1rem;cursor:pointer;border-radius:4px;border:1px solid #666;background:#eee}
button.copy{padding:.3rem .6rem;font-size:.9rem;margin-left:.3rem;background:#def}
#result{margin-top:1.5rem}
.row{display:flex;align-items:center;margin-bottom:.4rem}
.row label{width:14rem}
</style>
<script>
async function copy(id){
const val=document.getElementById(id).value;
await navigator.clipboard.writeText(val);
const btn=document.getElementById(id+"Btn");
const old=btn.textContent;
btn.textContent="✔ kopiert";
setTimeout(()=>btn.textContent=old,1200);
}
</script>
</head>
<body>
<h1>IPv4  IPv6Mapper</h1>
<form action="/convert" method="post">
<input type="text" name="ipv4" placeholder="%s" value="{{.IPv4}}" required />
<button type="submit">Umrechnen</button>
</form>
{{if .HaveResult}}
<div id="result">
<h2>Windows 11Eingaben</h2>
<div class="row">
<label for="ip">IPAdresse</label>
<input readonly id="ip" value="{{.IPv6}}" />
<button type="button" class="copy" id="ipBtn" onclick="copy('ip')">Kopieren</button>
</div>
<div class="row">
<label for="pl">Subnetzpräfixlänge</label>
<input readonly id="pl" value="96" />
<button type="button" class="copy" id="plBtn" onclick="copy('pl')">Kopieren</button>
</div>
<div class="row">
<label for="gw">Gateway (Bleibt vorerst leer!)</label>
<input readonly id="gw" value="{{.Gateway}}" />
<button type="button" class="copy" id="gwBtn" onclick="copy('gw')">Kopieren</button>
</div>
<div class="row">
<label for="dns1">Bevorzugter DNS</label>
<input readonly id="dns1" value="{{.DNS1}}" />
<button type="button" class="copy" id="dns1Btn" onclick="copy('dns1')">Kopieren</button>
</div>
<div class="row">
<label for="dns2">Alternativer DNS</label>
<input readonly id="dns2" value="{{.DNS2}}" />
<button type="button" class="copy" id="dns2Btn" onclick="copy('dns2')">Kopieren</button>
</div>
</div>
{{end}}
{{if .Error}}
<p style="color:#b00">Fehler: {{.Error}}</p>
{{end}}
<p style="margin-top:1.5rem">Aktives Präfix: <code>%s</code> (/96)</p>
</body>
</html>`, pageIP, ulaPrefix)
pageTemplate = template.Must(template.New("page").Parse(html))
}
// embedIPv4 converts a dotted IPv4 string into an IPv6 address within ulaPrefix/96.
func embedIPv4(ipv4 string) (string, error) {
ip := net.ParseIP(ipv4).To4()
if ip == nil {
return "", fmt.Errorf("'%s' ist keine gültige IPv4-Adresse", ipv4)
}
hi := uint16(ip[0])<<8 | uint16(ip[1])
lo := uint16(ip[2])<<8 | uint16(ip[3])
return fmt.Sprintf("%s%x:%x", ulaPrefix, hi, lo), nil
}
func renderPage(w http.ResponseWriter, d viewData) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := pageTemplate.Execute(w, d); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}