1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
package main
import (
"bytes"
"fmt"
"os"
"os/exec"
"github.com/katalix/go-l2tp/l2tp"
)
var _ pseudowire = (*pppDaemon)(nil)
type pppDaemon struct {
session l2tp.Session
fd int
file *os.File
cmd *exec.Cmd
stdoutBuf *bytes.Buffer
stderrBuf *bytes.Buffer
}
func pppdExitCodeString(err error) string {
// ref: pppd(8) section EXIT STATUS
switch err.Error() {
case "exit status 0":
return "pppd established successfully and terminated at peer's request"
case "exit status 1":
return "immediately fatal error (e.g. essential system call failed, or out of memory)"
case "exit status 2":
return "error detected during options parsing/processing"
case "exit status 3":
return "pppd is not setuid-root and the invoking user is not root"
case "exit status 4":
return "the kernel does not support PPP (possibly the module is not loaded or unavailable)"
case "exit status 5":
return "pppd terminated due to SIGINT, SIGTERM, or SIGHUP signal"
case "exit status 6":
return "the serial port could not be locked"
case "exit status 7":
return "the serial port could not be opened"
case "exit status 8":
return "the connect script returned a non-zero exit status"
case "exit status 9":
return "the command specified as an argument to the pty option could not be run"
case "exit status 10":
return "PPP negotiation failed (that is, didn't reach the point where at least one network protocol was running)"
case "exit status 11":
return "the peer system failed or refused to authenticate itself"
case "exit status 12":
return "the link was established successfully and terminated because it was idle"
case "exit status 13":
return "the link was established successfully and terminated because the connect time limit was reached"
case "exit status 14":
return "callback was negotiated and an incoming call should arrive shortly"
case "exit status 15":
return "the link was terminated because the peer is not responding to echo requests"
case "exit status 16":
return "the link was terminated by the modem hanging up"
case "exit status 17":
return "the ppp negotiation failed because serial loopback was detected"
case "exit status 18":
return "the init script returned a non-zero exit status"
case "exit status 19":
return "we failed to authenticate ourselves to the peer"
}
return err.Error()
}
func newPPPDaemon(session l2tp.Session, tunnelID, sessionID, peerTunnelID, peerSessionID l2tp.ControlConnID) (*pppDaemon, error) {
fd, err := socketPPPoL2TPv4(tunnelID, sessionID, peerTunnelID, peerSessionID)
if err != nil {
return nil, fmt.Errorf("failed to create PPPoL2TP socket: %v", err)
}
var stdout, stderr bytes.Buffer
file := os.NewFile(uintptr(fd), "pppol2tp")
cmd := exec.Command(
"/usr/sbin/pppd",
"plugin", "pppol2tp.so",
"pppol2tp", "3",
"pppol2tp_tunnel_id", fmt.Sprintf("%v", tunnelID),
"pppol2tp_session_id", fmt.Sprintf("%v", sessionID),
"nodetach")
cmd.Stdout = &stdout
cmd.Stderr = &stderr
cmd.ExtraFiles = append(cmd.ExtraFiles, file)
return &pppDaemon{
session: session,
fd: int(fd),
file: file,
cmd: cmd,
stdoutBuf: &stdout,
stderrBuf: &stderr,
}, nil
}
func (pppd *pppDaemon) close() {
pppd.cmd.Process.Signal(os.Interrupt)
}
func (pppd *pppDaemon) getSession() l2tp.Session {
return pppd.session
}
|