diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..20912ac --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,51 @@ +name: release-tag +on: + push: + branches: + - 'main' +jobs: + release-image: + runs-on: ubuntu-fast + env: + DOCKER_ORG: ${{ vars.DOCKER_ORG }} + DOCKER_LATEST: latest + RUNNER_TOOL_CACHE: /toolcache + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker BuildX + uses: docker/setup-buildx-action@v2 + with: # replace it with your local IP + config-inline: | + [registry."${{ vars.DOCKER_REGISTRY }}"] + http = true + insecure = true + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + registry: ${{ vars.DOCKER_REGISTRY }} # replace it with your local IP + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Get Meta + id: meta + run: | + echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT + echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT + + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + file: ./Dockerfile + platforms: | + linux/amd64 + push: true + tags: | # replace it with your local IP and tags + ${{ vars.DOCKER_REGISTRY }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }} + ${{ vars.DOCKER_REGISTRY }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e206835 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM golang:1.24.1 +WORKDIR /app +COPY go.mod ./ +RUN go mod download +COPY *.go ./ +RUN CGO_ENABLED=0 GOOS=linux go build -o /goprg +EXPOSE 8080 +CMD ["/goprg"] \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1f0c71e --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.send.nrw/StadtHilden/ipv6calculator + +go 1.23.1 diff --git a/main.go b/main.go new file mode 100644 index 0000000..935c74c --- /dev/null +++ b/main.go @@ -0,0 +1,96 @@ +package main + +import ( + "fmt" + "html/template" + "log" + "net" + "net/http" +) + +const ( + listenAddr = ":8080" // server port + ulaPrefix = "fdcb:7de3:a12a:0::" // fixed ULA /96 prefix +) + +// pageTemplate is served for both GET (empty result) and POST (with result). +var pageTemplate = template.Must(template.New("page").Parse(` + + + +IPv4 → IPv6‑Mapper + + + +

IPv4 → IPv6‑Mapper

+
+ + +
+ {{if .IPv6}} +
IPv6‑Adresse: {{.IPv6}}
+ {{end}} + {{if .Error}} +
Fehler: {{.Error}}
+ {{end}} +

Präfix: ` + ulaPrefix + `   (feste /96‑Zuordnung)

+ +`)) + +// viewData transports data into the page template. +type viewData struct { + IPv4 string + IPv6 string + Error string +} + +func main() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + // Empty page on root + 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.IPv6 = ipv6 + } + renderPage(w, data) + }) + + log.Printf("Server läuft auf http://localhost%s …", listenAddr) + log.Fatal(http.ListenAndServe(listenAddr, nil)) +} + +// embedIPv4 converts an IPv4 dotted string into the ulaPrefix‑based IPv6 address. +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) + } + first := uint16(ip[0])<<8 | uint16(ip[1]) // High 16 bits + second := uint16(ip[2])<<8 | uint16(ip[3]) // Low 16 bits + return fmt.Sprintf("%s%x:%x", ulaPrefix, first, second), 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) + } +}