mirror of
https://github.com/bettercap/bettercap
synced 2025-08-14 02:36:57 -07:00
misc: small fix or general refactoring i did not bother commenting
This commit is contained in:
parent
b0a197b377
commit
17ba1be16c
12 changed files with 239 additions and 498 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -15,4 +15,5 @@ stage/
|
|||
/snap
|
||||
.idea
|
||||
/cover.out
|
||||
/can-data
|
||||
/can-data
|
||||
/test*.yml
|
|
@ -1,26 +0,0 @@
|
|||
- name: TEST_NAME
|
||||
service: _ipps._tcp
|
||||
domain: local.
|
||||
port: 6631
|
||||
records:
|
||||
- txtvers=1
|
||||
- ty=EPSON XP-630 Series
|
||||
- usb_MFG=EPSON
|
||||
- usb_MDL=XP-630 Series
|
||||
- product=(EPSON XP-630 Series)
|
||||
- pdl=application/octet-stream,image/pwg-raster,image/urf,image/jpeg
|
||||
- rp=ipp/print
|
||||
- qtotal=1
|
||||
- Color=T
|
||||
- Duplex=T
|
||||
- Scan=T
|
||||
- Fax=F
|
||||
- kind=document,envelope,label,photo
|
||||
- PaperMax=legal-A4
|
||||
- URF=CP1,MT1-3-5-8-10-11-12,PQ4-5,OB9,OFU0,RS360,SRGB24,W8,DM3,IS1-7,V1.4
|
||||
- mopria-certified=1.2
|
||||
- priority=30
|
||||
- adminurl=http://EPSON59F5BA.local.:80/PRESENTATION/BONJOUR
|
||||
- note=
|
||||
- UUID=cfe92100-67c4-11d4-a45f-44d24459f5ba
|
||||
- TLS=1.2
|
|
@ -1,27 +0,0 @@
|
|||
- name: TEST_NAME
|
||||
service: _ipps._tcp
|
||||
domain: local.
|
||||
port: 6631
|
||||
responder: 134.122.95.96
|
||||
records:
|
||||
- txtvers=1
|
||||
- ty=EPSON XP-630 Series
|
||||
- usb_MFG=EPSON
|
||||
- usb_MDL=XP-630 Series
|
||||
- product=(EPSON XP-630 Series)
|
||||
- pdl=application/octet-stream,image/pwg-raster,image/urf,image/jpeg
|
||||
- rp=ipp/print
|
||||
- qtotal=1
|
||||
- Color=T
|
||||
- Duplex=T
|
||||
- Scan=T
|
||||
- Fax=F
|
||||
- kind=document,envelope,label,photo
|
||||
- PaperMax=legal-A4
|
||||
- URF=CP1,MT1-3-5-8-10-11-12,PQ4-5,OB9,OFU0,RS360,SRGB24,W8,DM3,IS1-7,V1.4
|
||||
- mopria-certified=1.2
|
||||
- priority=30
|
||||
- adminurl=http://EPSON59F5BA.local.:80/PRESENTATION/BONJOUR
|
||||
- note=
|
||||
- UUID=cfe92100-67c4-11d4-a45f-44d24459f5ba
|
||||
- TLS=1.2
|
|
@ -12,10 +12,10 @@ import (
|
|||
|
||||
type Handler struct {
|
||||
TLS bool
|
||||
Handle func(mod *ZeroGod, client net.Conn, srvHost string, srvPort int, srvTLS bool)
|
||||
Handle func(ctx *HandlerContext)
|
||||
}
|
||||
|
||||
// TODO: add more and possibly autodetect from peeking at the first bytes sent by the client
|
||||
// TODO: possibly autodetect from peeking at the first bytes sent by the client
|
||||
var TCP_HANDLERS = map[string]Handler{
|
||||
"_ipp": {
|
||||
Handle: ippClientHandler,
|
||||
|
@ -28,27 +28,38 @@ var TCP_HANDLERS = map[string]Handler{
|
|||
}
|
||||
|
||||
type Acceptor struct {
|
||||
mod *ZeroGod
|
||||
srvHost string
|
||||
port uint16
|
||||
service string
|
||||
tlsConfig *tls.Config
|
||||
listener net.Listener
|
||||
running bool
|
||||
context context.Context
|
||||
ctxCancel context.CancelFunc
|
||||
handler Handler
|
||||
mod *ZeroGod
|
||||
srvHost string
|
||||
port uint16
|
||||
service string
|
||||
tlsConfig *tls.Config
|
||||
listener net.Listener
|
||||
running bool
|
||||
context context.Context
|
||||
ctxCancel context.CancelFunc
|
||||
handler Handler
|
||||
ippAttributes map[string]string
|
||||
}
|
||||
|
||||
func NewAcceptor(mod *ZeroGod, service string, srvHost string, port uint16, tlsConfig *tls.Config) *Acceptor {
|
||||
type HandlerContext struct {
|
||||
mod *ZeroGod
|
||||
client net.Conn
|
||||
srvHost string
|
||||
srvPort int
|
||||
srvTLS bool
|
||||
ippAttributes map[string]string
|
||||
}
|
||||
|
||||
func NewAcceptor(mod *ZeroGod, service string, srvHost string, port uint16, tlsConfig *tls.Config, ippAttributes map[string]string) *Acceptor {
|
||||
context, ctcCancel := context.WithCancel(context.Background())
|
||||
acceptor := Acceptor{
|
||||
mod: mod,
|
||||
port: port,
|
||||
service: service,
|
||||
context: context,
|
||||
ctxCancel: ctcCancel,
|
||||
srvHost: srvHost,
|
||||
mod: mod,
|
||||
port: port,
|
||||
service: service,
|
||||
context: context,
|
||||
ctxCancel: ctcCancel,
|
||||
srvHost: srvHost,
|
||||
ippAttributes: ippAttributes,
|
||||
}
|
||||
|
||||
for svcName, svcHandler := range TCP_HANDLERS {
|
||||
|
@ -90,7 +101,14 @@ func (a *Acceptor) Start() (err error) {
|
|||
}
|
||||
} else {
|
||||
a.mod.Info("accepted connection for service %s (port %d): %v", tui.Green(a.service), a.port, conn.RemoteAddr())
|
||||
go a.handler.Handle(a.mod, conn, a.srvHost, int(a.port), a.tlsConfig != nil)
|
||||
go a.handler.Handle(&HandlerContext{
|
||||
mod: a.mod,
|
||||
client: conn,
|
||||
srvHost: a.srvHost,
|
||||
srvPort: int(a.port),
|
||||
srvTLS: a.tlsConfig != nil,
|
||||
ippAttributes: a.ippAttributes,
|
||||
})
|
||||
}
|
||||
}
|
||||
a.mod.Debug("tcp listener for port %d (%s) stopped", a.port, tui.Green(a.service))
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -13,15 +12,13 @@ import (
|
|||
tls_utils "github.com/bettercap/bettercap/v2/tls"
|
||||
"github.com/bettercap/bettercap/v2/zeroconf"
|
||||
"github.com/evilsocket/islazy/fs"
|
||||
"github.com/evilsocket/islazy/tui"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Advertiser struct {
|
||||
Filename string
|
||||
|
||||
Services []ServiceData
|
||||
Servers []*zeroconf.Server
|
||||
Services []*ServiceData
|
||||
Acceptors []*Acceptor
|
||||
}
|
||||
|
||||
|
@ -99,7 +96,7 @@ func (mod *ZeroGod) startAdvertiser(fileName string) error {
|
|||
return fmt.Errorf("could not read %s: %v", fileName, err)
|
||||
}
|
||||
|
||||
var services []ServiceData
|
||||
var services []*ServiceData
|
||||
if err = yaml.Unmarshal(data, &services); err != nil {
|
||||
return fmt.Errorf("could not deserialize %s: %v", fileName, err)
|
||||
}
|
||||
|
@ -109,101 +106,47 @@ func (mod *ZeroGod) startAdvertiser(fileName string) error {
|
|||
advertiser := &Advertiser{
|
||||
Filename: fileName,
|
||||
Services: services,
|
||||
Servers: make([]*zeroconf.Server, 0),
|
||||
Acceptors: make([]*Acceptor, 0),
|
||||
}
|
||||
|
||||
svcChan := make(chan setupResult)
|
||||
|
||||
// paralleize initialization
|
||||
for _, svc := range services {
|
||||
go func(svc ServiceData) {
|
||||
mod.Info("unregistering instance %s ...", tui.Yellow(svc.FullName()))
|
||||
|
||||
svcChan := make(chan error)
|
||||
for _, svc := range advertiser.Services {
|
||||
go func(svc *ServiceData) {
|
||||
// deregister the service from the network first
|
||||
if err := svc.Unregister(); err != nil {
|
||||
svcChan <- setupResult{err: fmt.Errorf("could not unregister service %s: %v", svc.FullName(), err)}
|
||||
if err := svc.Unregister(mod); err != nil {
|
||||
svcChan <- fmt.Errorf("could not unregister service %s: %v", svc.FullName(), err)
|
||||
return
|
||||
}
|
||||
|
||||
// give some time to the network to adjust
|
||||
time.Sleep(time.Duration(1) * time.Second)
|
||||
|
||||
var server *zeroconf.Server
|
||||
|
||||
// now create it again to actually advertise
|
||||
if svc.Responder == "" {
|
||||
// use our own IP
|
||||
if server, err = zeroconf.Register(
|
||||
svc.Name,
|
||||
svc.Service,
|
||||
svc.Domain,
|
||||
svc.Port,
|
||||
svc.Records,
|
||||
nil); err != nil {
|
||||
svcChan <- setupResult{err: fmt.Errorf("could not create service %s: %v", svc.FullName(), err)}
|
||||
return
|
||||
}
|
||||
mod.Info("advertising %s with responder=%s port=%d",
|
||||
tui.Yellow(svc.FullName()),
|
||||
tui.Red(svc.Responder),
|
||||
svc.Port)
|
||||
// register it
|
||||
if err := svc.Register(mod); err != nil {
|
||||
svcChan <- err
|
||||
} else {
|
||||
responderHostName := ""
|
||||
|
||||
// try first to do a reverse DNS of the ip
|
||||
if addr, err := net.LookupAddr(svc.Responder); err == nil && len(addr) > 0 {
|
||||
responderHostName = addr[0]
|
||||
} else {
|
||||
mod.Debug("could not get responder %s reverse dns entry: %v", svc.Responder, err)
|
||||
}
|
||||
|
||||
// if we don't have a host, create a .nip.io representation
|
||||
if responderHostName == "" {
|
||||
responderHostName = fmt.Sprintf("%s.nip.io.", strings.ReplaceAll(svc.Responder, ".", "-"))
|
||||
}
|
||||
|
||||
// use external responder
|
||||
if server, err = zeroconf.RegisterExternalResponder(
|
||||
svc.Name,
|
||||
svc.Service,
|
||||
svc.Domain,
|
||||
svc.Port,
|
||||
responderHostName,
|
||||
[]string{svc.Responder},
|
||||
svc.Records,
|
||||
nil); err != nil {
|
||||
svcChan <- setupResult{err: fmt.Errorf("could not create service %s: %v", svc.FullName(), err)}
|
||||
return
|
||||
}
|
||||
|
||||
mod.Info("advertising %s with responder=%s hostname=%s port=%d",
|
||||
tui.Yellow(svc.FullName()),
|
||||
tui.Red(svc.Responder),
|
||||
tui.Yellow(responderHostName),
|
||||
svc.Port)
|
||||
}
|
||||
|
||||
svcChan <- setupResult{
|
||||
server: server,
|
||||
svcChan <- nil
|
||||
}
|
||||
}(svc)
|
||||
}
|
||||
|
||||
for res := range svcChan {
|
||||
if res.err != nil {
|
||||
return res.err
|
||||
got := 0
|
||||
for err := range svcChan {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
advertiser.Servers = append(advertiser.Servers, res.server)
|
||||
if len(advertiser.Servers) == len(advertiser.Services) {
|
||||
got++
|
||||
if got == len(advertiser.Services) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// now create the tcp acceptors for entries without an explicit responder address
|
||||
for _, svc := range advertiser.Services {
|
||||
// if no external responder has been specified
|
||||
if svc.Responder == "" {
|
||||
acceptor := NewAcceptor(mod, svc.FullName(), hostName, uint16(svc.Port), tlsConfig)
|
||||
acceptor := NewAcceptor(mod, svc.FullName(), hostName, uint16(svc.Port), tlsConfig, svc.IPP)
|
||||
if err := acceptor.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -225,9 +168,8 @@ func (mod *ZeroGod) stopAdvertiser() error {
|
|||
|
||||
mod.Info("stopping %d services ...", len(mod.advertiser.Services))
|
||||
|
||||
for key, server := range mod.advertiser.Servers {
|
||||
mod.Info("stopping %s ...", key)
|
||||
server.Shutdown()
|
||||
for _, service := range mod.advertiser.Services {
|
||||
service.Unregister(mod)
|
||||
}
|
||||
|
||||
mod.Info("all services stopped")
|
||||
|
|
|
@ -42,7 +42,6 @@ func NewZeroGod(s *session.Session) *ZeroGod {
|
|||
return mod.Stop()
|
||||
}))
|
||||
|
||||
// TODO: add autocomplete
|
||||
mod.AddHandler(session.NewModuleHandler("zerogod.show", "",
|
||||
"Show discovered services.",
|
||||
func(args []string) error {
|
||||
|
@ -55,6 +54,7 @@ func NewZeroGod(s *session.Session) *ZeroGod {
|
|||
return mod.show("", true)
|
||||
}))
|
||||
|
||||
// TODO: add autocomplete
|
||||
mod.AddHandler(session.NewModuleHandler("zerogod.show ADDRESS", "zerogod.show (.+)",
|
||||
"Show discovered services given an ip address.",
|
||||
func(args []string) error {
|
||||
|
|
|
@ -23,13 +23,11 @@ func (mod *ZeroGod) updateEndpointMeta(address string, endpoint *network.Endpoin
|
|||
meta[fmt.Sprintf("mdns:%s:name", svcType)] = svc.ServiceName()
|
||||
meta[fmt.Sprintf("mdns:%s:hostname", svcType)] = svc.HostName
|
||||
|
||||
// TODO: include all
|
||||
if len(svc.AddrIPv4) > 0 {
|
||||
meta[fmt.Sprintf("mdns:%s:ipv4", svcType)] = svc.AddrIPv4[0].String()
|
||||
for i, ip := range svc.AddrIPv4 {
|
||||
meta[fmt.Sprintf("mdns:%s:ipv4[%d]", svcType, i)] = ip.String()
|
||||
}
|
||||
|
||||
if len(svc.AddrIPv6) > 0 {
|
||||
meta[fmt.Sprintf("mdns:%s:ipv6", svcType)] = svc.AddrIPv6[0].String()
|
||||
for i, ip := range svc.AddrIPv6 {
|
||||
meta[fmt.Sprintf("mdns:%s:ipv6[%d]", svcType, i)] = ip.String()
|
||||
}
|
||||
|
||||
meta[fmt.Sprintf("mdns:%s:port", svcType)] = fmt.Sprintf("%d", svc.Port)
|
||||
|
|
|
@ -2,7 +2,6 @@ package zerogod
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func Dump(by []byte) string {
|
||||
|
@ -51,19 +50,19 @@ func viewString(b []byte) string {
|
|||
return string(r)
|
||||
}
|
||||
|
||||
func handleGenericTCP(mod *ZeroGod, client net.Conn, srvHost string, srvPort int, srvTLS bool) {
|
||||
defer client.Close()
|
||||
func handleGenericTCP(ctx *HandlerContext) {
|
||||
defer ctx.client.Close()
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
if read, err := client.Read(buf); err != nil {
|
||||
mod.Error("error while reading from %v: %v", client.RemoteAddr(), err)
|
||||
if read, err := ctx.client.Read(buf); err != nil {
|
||||
ctx.mod.Error("error while reading from %v: %v", ctx.client.RemoteAddr(), err)
|
||||
break
|
||||
} else if read == 0 {
|
||||
mod.Error("error while reading from %v: no data", client.RemoteAddr())
|
||||
ctx.mod.Error("error while reading from %v: no data", ctx.client.RemoteAddr())
|
||||
break
|
||||
} else {
|
||||
mod.Info("read %d bytes from %v:\n%s\n", read, client.RemoteAddr(), Dump(buf[0:read]))
|
||||
ctx.mod.Info("read %d bytes from %v:\n%s\n", read, ctx.client.RemoteAddr(), Dump(buf[0:read]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
|
@ -49,6 +48,15 @@ var IPP_REQUEST_NAMES = map[int16]string{
|
|||
0x400D: "CUPS-Move-Job",
|
||||
}
|
||||
|
||||
var IPP_USER_ATTRIBUTES = map[string]string{
|
||||
"printer-name": "PRINTER_NAME",
|
||||
"printer-info": "PRINTER_INFO",
|
||||
"printer-make-and-model": "PRINTER_MAKE PRINTER_MODEL",
|
||||
"printer-location": "PRINTER_LOCATION",
|
||||
"printer-privacy-policy-uri": "https://www.bettercap.org/",
|
||||
"ppd-name": "everywhere",
|
||||
}
|
||||
|
||||
func init() {
|
||||
ipp.AttributeTagMapping["printer-uri-supported"] = ipp.TagUri
|
||||
ipp.AttributeTagMapping["uri-authentication-supported"] = ipp.TagKeyword
|
||||
|
@ -74,56 +82,57 @@ func init() {
|
|||
ipp.AttributeTagMapping["compression-supported"] = ipp.TagKeyword
|
||||
ipp.AttributeTagMapping["printer-privacy-policy-uri"] = ipp.TagUri
|
||||
ipp.AttributeTagMapping["printer-location"] = ipp.TagText
|
||||
ipp.AttributeTagMapping["ppd-name"] = ipp.TagName
|
||||
}
|
||||
|
||||
func ippClientHandler(mod *ZeroGod, client net.Conn, srvHost string, srvPort int, srvTLS bool) {
|
||||
defer client.Close()
|
||||
func ippClientHandler(ctx *HandlerContext) {
|
||||
defer ctx.client.Close()
|
||||
|
||||
buf := make([]byte, 4096)
|
||||
|
||||
// read raw request
|
||||
read, err := client.Read(buf)
|
||||
read, err := ctx.client.Read(buf)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return
|
||||
}
|
||||
mod.Error("error while reading from %v: %v", client.RemoteAddr(), err)
|
||||
ctx.mod.Error("error while reading from %v: %v", ctx.client.RemoteAddr(), err)
|
||||
return
|
||||
} else if read == 0 {
|
||||
mod.Error("error while reading from %v: no data", client.RemoteAddr())
|
||||
ctx.mod.Error("error while reading from %v: no data", ctx.client.RemoteAddr())
|
||||
return
|
||||
}
|
||||
|
||||
raw_req := buf[0:read]
|
||||
|
||||
mod.Debug("read %d bytes from %v:\n%s\n", read, client.RemoteAddr(), Dump(raw_req))
|
||||
ctx.mod.Debug("read %d bytes from %v:\n%s\n", read, ctx.client.RemoteAddr(), Dump(raw_req))
|
||||
|
||||
// parse as http
|
||||
reader := bufio.NewReader(bytes.NewReader(raw_req))
|
||||
http_req, err := http.ReadRequest(reader)
|
||||
if err != nil {
|
||||
mod.Error("error while parsing http request from %v: %v", client.RemoteAddr(), err)
|
||||
ctx.mod.Error("error while parsing http request from %v: %v", ctx.client.RemoteAddr(), err)
|
||||
return
|
||||
}
|
||||
|
||||
mod.Info("%v -> %s", client.RemoteAddr(), tui.Green(http_req.UserAgent()))
|
||||
ctx.mod.Info("%v -> %s", ctx.client.RemoteAddr(), tui.Green(http_req.UserAgent()))
|
||||
|
||||
ipp_body := http_req.Body
|
||||
|
||||
// check for an Expect 100-continue
|
||||
if http_req.Header.Get("Expect") == "100-continue" {
|
||||
// inform the client we're ready to read the request body
|
||||
client.Write([]byte("HTTP/1.1 100 Continue\r\n\r\n"))
|
||||
ctx.client.Write([]byte("HTTP/1.1 100 Continue\r\n\r\n"))
|
||||
// read the body
|
||||
read, err := client.Read(buf)
|
||||
read, err := ctx.client.Read(buf)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return
|
||||
}
|
||||
mod.Error("error while reading ipp body from %v: %v", client.RemoteAddr(), err)
|
||||
ctx.mod.Error("error while reading ipp body from %v: %v", ctx.client.RemoteAddr(), err)
|
||||
return
|
||||
} else if read == 0 {
|
||||
mod.Error("error while reading ipp body from %v: no data", client.RemoteAddr())
|
||||
ctx.mod.Error("error while reading ipp body from %v: no data", ctx.client.RemoteAddr())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -133,7 +142,7 @@ func ippClientHandler(mod *ZeroGod, client net.Conn, srvHost string, srvPort int
|
|||
// parse as IPP
|
||||
ipp_req, err := ipp.NewRequestDecoder(ipp_body).Decode(nil)
|
||||
if err != nil {
|
||||
mod.Error("error while parsing ip request from %v: %v", client.RemoteAddr(), err)
|
||||
ctx.mod.Error("error while parsing ip request from %v: %v", ctx.client.RemoteAddr(), err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -142,24 +151,24 @@ func ippClientHandler(mod *ZeroGod, client net.Conn, srvHost string, srvPort int
|
|||
ipp_op_name = name
|
||||
}
|
||||
|
||||
mod.Info("%v op=%s attributes=%v", client.RemoteAddr(), tui.Bold(ipp_op_name), ipp_req.OperationAttributes)
|
||||
ctx.mod.Info("%v op=%s attributes=%v", ctx.client.RemoteAddr(), tui.Bold(ipp_op_name), ipp_req.OperationAttributes)
|
||||
|
||||
switch ipp_req.Operation {
|
||||
// Get-Printer-Attributes
|
||||
case 0x000B:
|
||||
ippOnGetPrinterAttributes(mod, client, ipp_req, srvHost, srvPort, srvTLS)
|
||||
ippOnGetPrinterAttributes(ctx, ipp_req)
|
||||
|
||||
default:
|
||||
ippOnUnhandledRequest(mod, client, ipp_req, ipp_op_name)
|
||||
ippOnUnhandledRequest(ctx, ipp_req, ipp_op_name)
|
||||
}
|
||||
}
|
||||
|
||||
func ippSendResponse(mod *ZeroGod, client net.Conn, response *ipp.Response) {
|
||||
mod.Debug("SENDING %++v", *response)
|
||||
func ippSendResponse(ctx *HandlerContext, response *ipp.Response) {
|
||||
ctx.mod.Debug("SENDING %++v", *response)
|
||||
|
||||
resp_data, err := response.Encode()
|
||||
if err != nil {
|
||||
mod.Error("error while encoding ipp response: %v", err)
|
||||
ctx.mod.Error("error while encoding ipp response: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -172,29 +181,29 @@ func ippSendResponse(mod *ZeroGod, client net.Conn, response *ipp.Response) {
|
|||
}
|
||||
|
||||
for _, header := range headers {
|
||||
if _, err := client.Write(header); err != nil {
|
||||
mod.Error("error while writing header: %v", err)
|
||||
if _, err := ctx.client.Write(header); err != nil {
|
||||
ctx.mod.Error("error while writing header: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = client.Write(resp_data); err != nil {
|
||||
mod.Error("error while writing ipp response data: %v", err)
|
||||
if _, err = ctx.client.Write(resp_data); err != nil {
|
||||
ctx.mod.Error("error while writing ipp response data: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mod.Debug("sent %d of ipp response to %v", len(resp_data), client.RemoteAddr())
|
||||
ctx.mod.Debug("sent %d of ipp response to %v", len(resp_data), ctx.client.RemoteAddr())
|
||||
}
|
||||
|
||||
func ippOnUnhandledRequest(mod *ZeroGod, client net.Conn, ipp_req *ipp.Request, ipp_op_name string) {
|
||||
ipp_resp := ipp.NewResponse(ipp.StatusErrorOperationNotSupported, ipp_req.RequestId)
|
||||
func ippOnUnhandledRequest(ctx *HandlerContext, ipp_req *ipp.Request, ipp_op_name string) {
|
||||
ctx.mod.Warning("unhandled request from %v: operation=%s", ctx.client.RemoteAddr(), ipp_op_name)
|
||||
|
||||
ippSendResponse(mod, client, ipp_resp)
|
||||
|
||||
mod.Warning("unhandled request from %v: operation=%s", client.RemoteAddr(), ipp_op_name)
|
||||
ippSendResponse(ctx, ipp.NewResponse(
|
||||
ipp.StatusErrorOperationNotSupported,
|
||||
ipp_req.RequestId))
|
||||
}
|
||||
|
||||
func ippOnGetPrinterAttributes(mod *ZeroGod, client net.Conn, ipp_req *ipp.Request, srvHost string, srvPort int, srvTLS bool) {
|
||||
func ippOnGetPrinterAttributes(ctx *HandlerContext, ipp_req *ipp.Request) {
|
||||
ipp_resp := ipp.NewResponse(ipp.StatusOk, ipp_req.RequestId)
|
||||
|
||||
// https://tools.ietf.org/html/rfc2911 section 3.1.4.2 Response Operation Attributes
|
||||
|
@ -211,52 +220,15 @@ func ippOnGetPrinterAttributes(mod *ZeroGod, client net.Conn, ipp_req *ipp.Reque
|
|||
},
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
"""
|
||||
marker-names (1setOf nameWithoutLanguage) = Black ink,Cyan ink,Magenta ink,Yellow ink
|
||||
marker-colors (1setOf nameWithoutLanguage) = #000000,#00FFFF,#FF00FF,#FFFF00
|
||||
marker-types (1setOf keyword) = ink-cartridge,ink-cartridge,ink-cartridge,ink-cartridge
|
||||
marker-low-levels (1setOf integer) = 15,15,15,15
|
||||
marker-high-levels (1setOf integer) = 100,100,100,100
|
||||
marker-levels (1setOf integer) = 57,94,95,95
|
||||
"""
|
||||
|
||||
markers = {
|
||||
(
|
||||
SectionEnum.printer,
|
||||
b'marker-names',
|
||||
TagEnum.text_without_language
|
||||
): [b'TestMarker'],
|
||||
(
|
||||
SectionEnum.printer,
|
||||
b'marker-colors',
|
||||
TagEnum.text_without_language
|
||||
): [b'#FF0000'],
|
||||
(
|
||||
SectionEnum.printer,
|
||||
b'marker-types',
|
||||
TagEnum.text_without_language
|
||||
): [b'ink-cartridge'],
|
||||
(
|
||||
SectionEnum.printer,
|
||||
b'marker-low-levels',
|
||||
TagEnum.integer
|
||||
): [Integer(15).bytes()],
|
||||
(
|
||||
SectionEnum.printer,
|
||||
b'marker-high-levels',
|
||||
TagEnum.integer
|
||||
): [Integer(100).bytes()],
|
||||
(
|
||||
SectionEnum.printer,
|
||||
b'marker-levels',
|
||||
TagEnum.integer
|
||||
): [Integer(66).bytes()],
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: allow customization of these attributes.
|
||||
// collect user attributes
|
||||
userProps := make(map[string]string)
|
||||
for name, defaultValue := range IPP_USER_ATTRIBUTES {
|
||||
if value, found := ctx.ippAttributes[name]; found {
|
||||
userProps[name] = value
|
||||
} else {
|
||||
userProps[name] = defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
// rfc2911 section 4.4
|
||||
ipp_resp.PrinterAttributes = []ipp.Attributes{
|
||||
|
@ -264,61 +236,58 @@ func ippOnGetPrinterAttributes(mod *ZeroGod, client net.Conn, ipp_req *ipp.Reque
|
|||
// custom
|
||||
"printer-name": []ipp.Attribute{
|
||||
{
|
||||
Value: "PRINTER_NAME",
|
||||
Value: userProps["printer-name"],
|
||||
Tag: ipp.TagName,
|
||||
},
|
||||
},
|
||||
"printer-info": []ipp.Attribute{
|
||||
{
|
||||
Value: "PRINTER_INFO",
|
||||
Value: userProps["printer-info"],
|
||||
Tag: ipp.TagText,
|
||||
},
|
||||
},
|
||||
"printer-make-and-model": []ipp.Attribute{
|
||||
{
|
||||
Value: "PRINTER_MAKE PRINTER_MODEL",
|
||||
Value: userProps["printer-make-and-model"],
|
||||
Tag: ipp.TagText,
|
||||
},
|
||||
},
|
||||
"printer-location": []ipp.Attribute{
|
||||
{
|
||||
Value: "PRINTER_LOCATION",
|
||||
Value: userProps["printer-location"],
|
||||
Tag: ipp.TagText,
|
||||
},
|
||||
},
|
||||
"printer-privacy-policy-uri": []ipp.Attribute{
|
||||
{
|
||||
Value: "https://www.google.com/",
|
||||
Value: userProps["printer-privacy-policy-uri"],
|
||||
Tag: ipp.TagUri,
|
||||
},
|
||||
},
|
||||
// constants
|
||||
/*
|
||||
"ppd-name": []ipp.Attribute{
|
||||
{
|
||||
Value: "everywhere",
|
||||
Tag: ipp.TagName,
|
||||
},
|
||||
"ppd-name": []ipp.Attribute{
|
||||
{
|
||||
Value: userProps["ppd-name"],
|
||||
Tag: ipp.TagName,
|
||||
},
|
||||
*/
|
||||
},
|
||||
"printer-uri-supported": []ipp.Attribute{
|
||||
{
|
||||
Value: fmt.Sprintf("%s://%s:%d/printer", ops.Ternary(srvTLS, "ipps", "ipp"), srvHost, srvPort),
|
||||
Value: fmt.Sprintf("%s://%s:%d/printer", ops.Ternary(ctx.srvTLS, "ipps", "ipp"), ctx.srvHost, ctx.srvPort),
|
||||
Tag: ipp.TagUri,
|
||||
},
|
||||
},
|
||||
"uri-security-supported": []ipp.Attribute{
|
||||
{
|
||||
Value: ops.Ternary(ctx.srvTLS, "tls", "none"),
|
||||
Tag: ipp.TagKeyword,
|
||||
},
|
||||
},
|
||||
"uri-authentication-supported": []ipp.Attribute{
|
||||
{
|
||||
Value: "none",
|
||||
Tag: ipp.TagKeyword,
|
||||
},
|
||||
},
|
||||
"uri-security-supported": []ipp.Attribute{
|
||||
{
|
||||
Value: ops.Ternary(srvTLS, "tls", "none"),
|
||||
Tag: ipp.TagKeyword,
|
||||
},
|
||||
},
|
||||
"printer-state": []ipp.Attribute{
|
||||
{
|
||||
Value: 3, // idle
|
||||
|
@ -424,5 +393,5 @@ func ippOnGetPrinterAttributes(mod *ZeroGod, client net.Conn, ipp_req *ipp.Reque
|
|||
},
|
||||
}
|
||||
|
||||
ippSendResponse(mod, client, ipp_resp)
|
||||
ippSendResponse(ctx, ipp_resp)
|
||||
}
|
||||
|
|
|
@ -3,38 +3,12 @@ package zerogod
|
|||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/bettercap/bettercap/v2/zeroconf"
|
||||
"github.com/evilsocket/islazy/str"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type ServiceData struct {
|
||||
Name string `yaml:"name"` // Instance name (e.g. "My web page")
|
||||
Service string `yaml:"service"` // Service name (e.g. _http._tcp.)
|
||||
Domain string `yaml:"domain"` // If blank, assumes "local"
|
||||
Port int `yaml:"port"` // Service port
|
||||
Records []string `yaml:"records,omitempty"` // Service DNS text records
|
||||
Responder string `yaml:"responder,omitempty"` // Optional IP to use instead of our tcp acceptor
|
||||
}
|
||||
|
||||
func (svc ServiceData) FullName() string {
|
||||
return fmt.Sprintf("%s.%s.%s",
|
||||
strings.Trim(svc.Name, "."),
|
||||
strings.Trim(svc.Service, "."),
|
||||
strings.Trim(svc.Domain, "."))
|
||||
}
|
||||
|
||||
func (svc ServiceData) Unregister() error {
|
||||
if server, err := zeroconf.Register(svc.Name, svc.Service, svc.Domain, svc.Port, svc.Records, nil); err != nil {
|
||||
return err
|
||||
} else {
|
||||
server.Shutdown()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func svcEntriesToData(services map[string]*zeroconf.ServiceEntry) []ServiceData {
|
||||
data := make([]ServiceData, 0)
|
||||
for _, svc := range services {
|
||||
|
|
100
modules/zerogod/zerogod_service.go
Normal file
100
modules/zerogod/zerogod_service.go
Normal file
|
@ -0,0 +1,100 @@
|
|||
package zerogod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/bettercap/bettercap/v2/zeroconf"
|
||||
"github.com/evilsocket/islazy/tui"
|
||||
)
|
||||
|
||||
type ServiceData struct {
|
||||
Name string `yaml:"name"` // Instance name (e.g. "My web page")
|
||||
Service string `yaml:"service"` // Service name (e.g. _http._tcp.)
|
||||
Domain string `yaml:"domain"` // If blank, assumes "local"
|
||||
Port int `yaml:"port"` // Service port
|
||||
Records []string `yaml:"records,omitempty"` // Service DNS text records
|
||||
Responder string `yaml:"responder,omitempty"` // Optional IP to use instead of our tcp acceptor
|
||||
IPP map[string]string `yaml:"ipp,omitempty"` // Optional IPP attributes map
|
||||
|
||||
server *zeroconf.Server
|
||||
}
|
||||
|
||||
func (svc ServiceData) FullName() string {
|
||||
return fmt.Sprintf("%s.%s.%s",
|
||||
strings.Trim(svc.Name, "."),
|
||||
strings.Trim(svc.Service, "."),
|
||||
strings.Trim(svc.Domain, "."))
|
||||
}
|
||||
|
||||
func (svc *ServiceData) Register(mod *ZeroGod) (err error) {
|
||||
// now create it again to actually advertise
|
||||
if svc.Responder == "" {
|
||||
// use our own IP
|
||||
if svc.server, err = zeroconf.Register(
|
||||
svc.Name,
|
||||
svc.Service,
|
||||
svc.Domain,
|
||||
svc.Port,
|
||||
svc.Records,
|
||||
nil); err != nil {
|
||||
return fmt.Errorf("could not create service %s: %v", svc.FullName(), err)
|
||||
}
|
||||
|
||||
mod.Info("advertising %s with responder=%s port=%d",
|
||||
tui.Yellow(svc.FullName()),
|
||||
tui.Red(svc.Responder),
|
||||
svc.Port)
|
||||
} else {
|
||||
responderHostName := ""
|
||||
// try first to do a reverse DNS of the ip
|
||||
if addr, err := net.LookupAddr(svc.Responder); err == nil && len(addr) > 0 {
|
||||
responderHostName = addr[0]
|
||||
} else {
|
||||
mod.Debug("could not get responder %s reverse dns entry: %v", svc.Responder, err)
|
||||
}
|
||||
|
||||
// if we don't have a host, create a .nip.io representation
|
||||
if responderHostName == "" {
|
||||
responderHostName = fmt.Sprintf("%s.nip.io.", strings.ReplaceAll(svc.Responder, ".", "-"))
|
||||
}
|
||||
|
||||
// use external responder
|
||||
if svc.server, err = zeroconf.RegisterExternalResponder(
|
||||
svc.Name,
|
||||
svc.Service,
|
||||
svc.Domain,
|
||||
svc.Port,
|
||||
responderHostName,
|
||||
[]string{svc.Responder},
|
||||
svc.Records,
|
||||
nil); err != nil {
|
||||
return fmt.Errorf("could not create service %s: %v", svc.FullName(), err)
|
||||
}
|
||||
|
||||
mod.Info("advertising %s with responder=%s hostname=%s port=%d",
|
||||
tui.Yellow(svc.FullName()),
|
||||
tui.Red(svc.Responder),
|
||||
tui.Yellow(responderHostName),
|
||||
svc.Port)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (svc *ServiceData) Unregister(mod *ZeroGod) error {
|
||||
mod.Info("unregistering instance %s ...", tui.Yellow(svc.FullName()))
|
||||
|
||||
err := (error)(nil)
|
||||
if svc.server == nil {
|
||||
// if we haven't been registered yet, create the server
|
||||
if svc.server, err = zeroconf.Register(svc.Name, svc.Service, svc.Domain, svc.Port, svc.Records, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
svc.server.Shutdown()
|
||||
|
||||
return nil
|
||||
}
|
207
test.yml
207
test.yml
|
@ -1,207 +0,0 @@
|
|||
EPSON\ XP-630\ Series-59F5BA-04._http._tcp.local.:
|
||||
servicerecord:
|
||||
instance: EPSON\ XP-630\ Series-59F5BA-04
|
||||
service: _http._tcp
|
||||
domain: local.
|
||||
hostname: EPSON59F5BA.local.
|
||||
port: 80
|
||||
text:
|
||||
- ""
|
||||
ttl: 4500
|
||||
addripv4:
|
||||
- 192.168.50.21
|
||||
addripv6:
|
||||
- fe80::46d2:44ff:fe59:f5ba
|
||||
EPSON\ XP-630\ Series-59F5BA-04._ipp._tcp.local.:
|
||||
servicerecord:
|
||||
instance: EPSON\ XP-630\ Series-59F5BA-04
|
||||
service: _ipp._tcp
|
||||
domain: local.
|
||||
hostname: EPSON59F5BA.local.
|
||||
port: 6633
|
||||
text:
|
||||
- txtvers=1
|
||||
- ty=EPSON XP-630 Series
|
||||
- usb_MFG=EPSON
|
||||
- usb_MDL=XP-630 Series
|
||||
- product=(EPSON XP-630 Series)
|
||||
- pdl=application/octet-stream,image/pwg-raster,image/urf,image/jpeg
|
||||
- rp=ipp/print
|
||||
- qtotal=1
|
||||
- Color=T
|
||||
- Duplex=T
|
||||
- Scan=T
|
||||
- Fax=F
|
||||
- kind=document,envelope,label,photo
|
||||
- PaperMax=legal-A4
|
||||
- URF=CP1,MT1-3-5-8-10-11-12,PQ4-5,OB9,OFU0,RS360,SRGB24,W8,DM3,IS1-7,V1.4
|
||||
- mopria-certified=1.2
|
||||
- priority=30
|
||||
- adminurl=http://EPSON59F5BA.local.:80/PRESENTATION/BONJOUR
|
||||
- note=
|
||||
- UUID=cfe92100-67c4-11d4-a45f-44d24459f5ba
|
||||
- TLS=1.2
|
||||
ttl: 4500
|
||||
addripv4:
|
||||
- 192.168.50.21
|
||||
addripv6:
|
||||
- fe80::46d2:44ff:fe59:f5ba
|
||||
EPSON\ XP-630\ Series-59F5BA-04._ipps._tcp.local.:
|
||||
servicerecord:
|
||||
instance: EPSON\ XP-630\ Series-59F5BA-04
|
||||
service: _ipps._tcp
|
||||
domain: local.
|
||||
hostname: EPSON59F5BA.local.
|
||||
port: 6631
|
||||
text:
|
||||
- txtvers=1
|
||||
- ty=EPSON XP-630 Series
|
||||
- usb_MFG=EPSON
|
||||
- usb_MDL=XP-630 Series
|
||||
- product=(EPSON XP-630 Series)
|
||||
- pdl=application/octet-stream,image/pwg-raster,image/urf,image/jpeg
|
||||
- rp=ipp/print
|
||||
- qtotal=1
|
||||
- Color=T
|
||||
- Duplex=T
|
||||
- Scan=T
|
||||
- Fax=F
|
||||
- kind=document,envelope,label,photo
|
||||
- PaperMax=legal-A4
|
||||
- URF=CP1,MT1-3-5-8-10-11-12,PQ4-5,OB9,OFU0,RS360,SRGB24,W8,DM3,IS1-7,V1.4
|
||||
- mopria-certified=1.2
|
||||
- priority=30
|
||||
- adminurl=http://EPSON59F5BA.local.:80/PRESENTATION/BONJOUR
|
||||
- note=
|
||||
- UUID=cfe92100-67c4-11d4-a45f-44d24459f5ba
|
||||
- TLS=1.2
|
||||
ttl: 4500
|
||||
addripv4:
|
||||
- 192.168.50.21
|
||||
addripv6:
|
||||
- fe80::46d2:44ff:fe59:f5ba
|
||||
EPSON\ XP-630\ Series-59F5BA-04._pdl-datastream._tcp.local.:
|
||||
servicerecord:
|
||||
instance: EPSON\ XP-630\ Series-59F5BA-04
|
||||
service: _pdl-datastream._tcp
|
||||
domain: local.
|
||||
hostname: EPSON59F5BA.local.
|
||||
port: 9100
|
||||
text:
|
||||
- txtvers=1
|
||||
- priority=40
|
||||
- ty=EPSON XP-630 Series
|
||||
- usb_MFG=EPSON
|
||||
- usb_MDL=XP-630 Series
|
||||
- product=(EPSON XP-630 Series)
|
||||
- pdl=raw
|
||||
- qtotal=1
|
||||
- adminurl=http://EPSON59F5BA.local.:80/PRESENTATION/BONJOUR
|
||||
- note=
|
||||
ttl: 4500
|
||||
addripv4:
|
||||
- 192.168.50.21
|
||||
addripv6:
|
||||
- fe80::46d2:44ff:fe59:f5ba
|
||||
EPSON\ XP-630\ Series-59F5BA-04._printer._tcp.local.:
|
||||
servicerecord:
|
||||
instance: EPSON\ XP-630\ Series-59F5BA-04
|
||||
service: _printer._tcp
|
||||
domain: local.
|
||||
hostname: EPSON59F5BA.local.
|
||||
port: 1515
|
||||
text:
|
||||
- txtvers=1
|
||||
- priority=50
|
||||
- ty=EPSON XP-630 Series
|
||||
- usb_MFG=EPSON
|
||||
- usb_MDL=XP-630 Series
|
||||
- product=(EPSON XP-630 Series)
|
||||
- pdl=raw
|
||||
- rp=auto
|
||||
- qtotal=1
|
||||
- adminurl=http://EPSON59F5BA.local.:80/PRESENTATION/BONJOUR
|
||||
- note=
|
||||
ttl: 4500
|
||||
addripv4:
|
||||
- 192.168.50.21
|
||||
addripv6:
|
||||
- fe80::46d2:44ff:fe59:f5ba
|
||||
EPSON\ XP-630\ Series-59F5BA-04._privet._tcp.local.:
|
||||
servicerecord:
|
||||
instance: EPSON\ XP-630\ Series-59F5BA-04
|
||||
service: _privet._tcp
|
||||
domain: local.
|
||||
hostname: EPSON59F5BA.local.
|
||||
port: 8081
|
||||
text:
|
||||
- txtvers=1
|
||||
- ty=EPSON XP-630 Series (EPSON59F5BA)
|
||||
- url=https://www.google.com/cloudprint
|
||||
- type=printer
|
||||
- id=0936a89f-33d7-80f5-c1bc-7421d40a78b5
|
||||
- cs=offline
|
||||
ttl: 4500
|
||||
addripv4:
|
||||
- 192.168.50.21
|
||||
addripv6:
|
||||
- fe80::46d2:44ff:fe59:f5ba
|
||||
EPSON\ XP-630\ Series-59F5BA-04._scanner._tcp.local.:
|
||||
servicerecord:
|
||||
instance: EPSON\ XP-630\ Series-59F5BA-04
|
||||
service: _scanner._tcp
|
||||
domain: local.
|
||||
hostname: EPSON59F5BA.local.
|
||||
port: 1865
|
||||
text:
|
||||
- txtvers=1
|
||||
- ty=EPSON XP-630 Series
|
||||
- adminurl=http://EPSON59F5BA.local.:80/PRESENTATION/BONJOUR
|
||||
- mfg=EPSON
|
||||
- mdl=XP-630 Series
|
||||
- UUID=cfe92100-67c4-11d4-a45f-44d24459f5ba
|
||||
- scannerAvailable=0
|
||||
- note=
|
||||
ttl: 4500
|
||||
addripv4:
|
||||
- 192.168.50.21
|
||||
addripv6:
|
||||
- fe80::46d2:44ff:fe59:f5ba
|
||||
EPSON\ XP-630\ Series-59F5BA-04._smb._tcp.local.:
|
||||
servicerecord:
|
||||
instance: EPSON\ XP-630\ Series-59F5BA-04
|
||||
service: _smb._tcp
|
||||
domain: local.
|
||||
hostname: EPSON59F5BA.local.
|
||||
port: 1445
|
||||
text: []
|
||||
ttl: 120
|
||||
addripv4:
|
||||
- 192.168.50.21
|
||||
addripv6:
|
||||
- fe80::46d2:44ff:fe59:f5ba
|
||||
EPSON\ XP-630\ Series-59F5BA-04._uscan._tcp.local.:
|
||||
servicerecord:
|
||||
instance: EPSON\ XP-630\ Series-59F5BA-04
|
||||
service: _uscan._tcp
|
||||
domain: local.
|
||||
hostname: EPSON59F5BA.local.
|
||||
port: 8443
|
||||
text:
|
||||
- txtvers=1
|
||||
- vers=2.5
|
||||
- representation=/PRESENTATION/AIRPRINT/PRINTER_128.PNG
|
||||
- rs=eSCL
|
||||
- ty=EPSON XP-630 Series
|
||||
- pdl=application/pdf,image/jpeg
|
||||
- cs=color,grayscale,binary
|
||||
- is=platen
|
||||
- duplex=F
|
||||
- adminurl=http://EPSON59F5BA.local.:80/PRESENTATION/BONJOUR
|
||||
- UUID=cfe92100-67c4-11d4-a45f-44d24459f5ba
|
||||
- note=
|
||||
ttl: 4500
|
||||
addripv4:
|
||||
- 192.168.50.21
|
||||
addripv6:
|
||||
- fe80::46d2:44ff:fe59:f5ba
|
Loading…
Add table
Add a link
Reference in a new issue