package main import ( "encoding/json" "log" "net/http" ) type loginChecker struct{ students []Student } type loginUpload struct { Username string Password string } func (l loginChecker) ServeHTTP(w http.ResponseWriter, r *http.Request) { if addr := r.Header.Get("X-Forwarded-For"); addr != "" { r.RemoteAddr = addr } log.Printf("%s \"%s %s\" [%s]\n", r.RemoteAddr, r.Method, r.URL.Path, r.UserAgent()) w.Header().Set("Content-Type", "text/plain") // Check request type and size if r.Method != "POST" { http.Error(w, "Invalid request", http.StatusBadRequest) return } else if r.ContentLength < 0 || r.ContentLength > 1023 { http.Error(w, "Request entity too large", http.StatusRequestEntityTooLarge) return } dec := json.NewDecoder(r.Body) var lu loginUpload if err := dec.Decode(&lu); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // Perform login check canContinue := false for _, std := range l.students { if std.Login == lu.Username { canContinue = true } } if !canContinue { log.Println("Login not found:", lu.Username, "at", r.RemoteAddr) http.Error(w, "Login not found in whitelist.", http.StatusUnauthorized) return } if err := l.lateLoginAction(lu.Username, r.RemoteAddr); err != nil { log.Println("Error on late login action:", err) http.Error(w, "Internal server error. Please retry in a few minutes", http.StatusInternalServerError) return } log.Println("Successful login of", lu.Username, "at", r.RemoteAddr) http.Error(w, "Success", http.StatusOK) } func (l loginChecker) lateLoginAction(username, remoteAddr string) error { // Find corresponding MAC var fname string spl := strings.SplitN(remoteAddr, ":", 2) if ip := net.ParseIP(spl[0]); ip == nil { return errors.New("Unable to parse given IPv4: " + spl[0]) } else if arptable, err := ARPAnalyze(); err != nil { return err } else if arpent := ARPContainsIP(arptable, ip); arpent == nil { return errors.New("Unable to find MAC in ARP table") } else { fname = fmt.Sprintf("%02x-%02x-%02x-%02x-%02x-%02x-%02x", arpent.HWType, arpent.HWAddress[0], arpent.HWAddress[1], arpent.HWAddress[2], arpent.HWAddress[3], arpent.HWAddress[4], arpent.HWAddress[5]) } if tpl, err := ioutil.ReadFile(path.Join(tftpDir, "pxelinux.cfg", "tpl")); err != nil { log.Println("Unable to open tpl: ", err) } else if file, err := os.OpenFile(path.Join(tftpDir, "pxelinux.cfg", fname), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0644)); err != nil { log.Println("Unable to open destination file: ", err) } else { defer file.Close() if configTmpl, err := template.New("pxelinux.cfg").Parse(string(tpl)); err != nil { log.Println("Cannot create template: ", err) } else if err := configTmpl.Execute(file, map[string]string{"username": username, "remoteAddr": remoteAddr, "fname": fname}); err != nil { log.Println("An error occurs during template execution: ", err) } } return nil }