mirror of
https://github.com/bettercap/bettercap
synced 2025-07-06 04:52:10 -07:00
new: new can module for CAN-bus
This commit is contained in:
parent
9937e797ae
commit
5fe3ef3d52
12 changed files with 755 additions and 3 deletions
3
go.mod
3
go.mod
|
@ -27,8 +27,6 @@ require (
|
|||
github.com/jpillora/go-tld v1.2.1
|
||||
github.com/kr/binarydist v0.1.0 // indirect
|
||||
github.com/malfunkt/iprange v0.9.0
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b
|
||||
github.com/miekg/dns v1.1.61
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
|
@ -37,6 +35,7 @@ require (
|
|||
github.com/stratoberry/go-gpsd v1.3.0
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
|
||||
github.com/thoj/go-ircevent v0.0.0-20210723090443-73e444401d64
|
||||
go.einride.tech/can v0.12.0
|
||||
golang.org/x/net v0.28.0
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
)
|
||||
|
|
32
go.sum
32
go.sum
|
@ -2,6 +2,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH
|
|||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
||||
github.com/adrianmo/go-nmea v1.9.0 h1:kCuerWLDIppltHNZ2HGdCGkqbmupYJYfE6indcGkcp8=
|
||||
github.com/adrianmo/go-nmea v1.9.0/go.mod h1:u8bPnpKt/D/5rll/5l9f6iDfeq5WZW0+/SXdkwix6Tg=
|
||||
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
github.com/antchfx/jsonquery v1.3.5 h1:243OSaQh02EfmASa3w3weKC9UaiD8RRzJhgfvq3q408=
|
||||
github.com/antchfx/jsonquery v1.3.5/go.mod h1:qH23yX2Jsj1/k378Yu/EOgPCNgJ35P9tiGOeQdt/GWc=
|
||||
github.com/antchfx/xpath v1.3.1 h1:PNbFuUqHwWl0xRjvUPjJ95Agbmdj2uzzIwmQKgu4oCk=
|
||||
|
@ -31,12 +33,15 @@ github.com/elazarl/goproxy/ext v0.0.0-20210110162100-a92cc753f88e h1:CQn2/8fi3km
|
|||
github.com/elazarl/goproxy/ext v0.0.0-20210110162100-a92cc753f88e/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/evilsocket/islazy v1.11.0 h1:B5w6uuS6ki6iDG+aH/RFeoMb8ijQh/pGabewqp2UeJ0=
|
||||
github.com/evilsocket/islazy v1.11.0/go.mod h1:muYH4x5MB5YRdkxnrOtrXLIBX6LySj1uFIqys94LKdo=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
github.com/florianl/go-nfqueue/v2 v2.0.0 h1:NTCxS9b0GSbHkWv1a7oOvZn679fsyDkaSkRvOYpQ9Oo=
|
||||
github.com/florianl/go-nfqueue/v2 v2.0.0/go.mod h1:M2tBLIj62QpwqjwV0qfcjqGOqP3qiTuXr2uSRBXH9Qk=
|
||||
github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe h1:8P+/htb3mwwpeGdJg69yBF/RofK7c6Fjz5Ypa/bTqbY=
|
||||
github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
|
@ -63,6 +68,7 @@ github.com/jpillora/go-tld v1.2.1 h1:kDKOkmXLlskqjcvNs7w5XHLep7c8WM7Xd4HQjxllVMk
|
|||
github.com/jpillora/go-tld v1.2.1/go.mod h1:plzIl7xr5UWKGy7R+giuv+L/nOjrPjsoWxy/ST9OBUk=
|
||||
github.com/kr/binarydist v0.1.0 h1:6kAoLA9FMMnNGSehX0s1PdjbEaACznAv/W219j2uvyo=
|
||||
github.com/kr/binarydist v0.1.0/go.mod h1:DY7S//GCoz1BCd0B0EVrinCKAZN3pXe+MDaIZbXQVgM=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
|
@ -99,26 +105,37 @@ github.com/robertkrimen/otto v0.2.1/go.mod h1:UPwtJ1Xu7JrLcZjNWN8orJaM5n5YEtqL//
|
|||
github.com/robertkrimen/otto v0.4.0 h1:/c0GRrK1XDPcgIasAsnlpBT5DelIeB9U/Z/JCQsgr7E=
|
||||
github.com/robertkrimen/otto v0.4.0/go.mod h1:uW9yN1CYflmUQYvAMS0m+ZiNo3dMzRUDQJX0jWbzgxw=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/shurcooL/go v0.0.0-20190704215121-7189cc372560/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/stratoberry/go-gpsd v1.3.0 h1:JxJOEC4SgD0QY65AE7B1CtJtweP73nqJghZeLNU9J+c=
|
||||
github.com/stratoberry/go-gpsd v1.3.0/go.mod h1:nVf/vTgfYxOMxiQdy9BtJjojbFRtG8H3wNula++VgkU=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/thoj/go-ircevent v0.0.0-20210723090443-73e444401d64 h1:l/T7dYuJEQZOwVOpjIXr1180aM9PZL/d1MnMVIxefX4=
|
||||
github.com/thoj/go-ircevent v0.0.0-20210723090443-73e444401d64/go.mod h1:Q1NAJOuRdQCqN/VIWdnaaEhV8LpeO2rtlBP7/iDJNII=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.einride.tech/can v0.12.0 h1:6MW9TKycSovWqJxcYHpZEiuFCGuAfpqApCzTS15KrPk=
|
||||
go.einride.tech/can v0.12.0/go.mod h1:5n3+AonCfUso6PfjD9l2d0W2LxTFjjHOnHAm+UMS9Ws=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
|
@ -126,7 +143,9 @@ golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5D
|
|||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
|
@ -138,10 +157,12 @@ golang.org/x/net v0.0.0-20190310074541-c10a0554eabf/go.mod h1:mL1N/T3taQHkDXs73r
|
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
|
@ -169,17 +190,20 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
|
||||
|
@ -188,6 +212,7 @@ golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXct
|
|||
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
|
@ -212,9 +237,12 @@ golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
|||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
|
@ -222,7 +250,9 @@ golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ
|
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/readline.v1 v1.0.0-20160726135117-62c6fe619375/go.mod h1:lNEQeAhU009zbRxng+XOj5ITVgY24WcbNnQopyfKoYQ=
|
||||
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
|
||||
|
@ -232,3 +262,5 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
|
|
84
modules/can/can.go
Normal file
84
modules/can/can.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
package can
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/bettercap/bettercap/session"
|
||||
"go.einride.tech/can/pkg/descriptor"
|
||||
"go.einride.tech/can/pkg/socketcan"
|
||||
)
|
||||
|
||||
type CANModule struct {
|
||||
session.SessionModule
|
||||
|
||||
deviceName string
|
||||
transport string
|
||||
dbcPath string
|
||||
dbc *descriptor.Database
|
||||
|
||||
conn net.Conn
|
||||
recv *socketcan.Receiver
|
||||
}
|
||||
|
||||
func NewCanModule(s *session.Session) *CANModule {
|
||||
mod := &CANModule{
|
||||
SessionModule: session.NewSessionModule("can", s),
|
||||
dbcPath: "",
|
||||
transport: "can",
|
||||
deviceName: "can0",
|
||||
}
|
||||
|
||||
mod.AddParam(session.NewStringParameter("can.device",
|
||||
mod.deviceName,
|
||||
"",
|
||||
"CAN-bus device."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("can.transport",
|
||||
mod.transport,
|
||||
"",
|
||||
"Network type, can be 'can' for SocketCAN or 'udp'."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("can.dbc_path",
|
||||
mod.dbcPath,
|
||||
"",
|
||||
"Optional path to DBC file for decoding."))
|
||||
|
||||
mod.AddHandler(session.NewModuleHandler("can.recon on", "",
|
||||
"Start CAN-bus discovery.",
|
||||
func(args []string) error {
|
||||
return mod.Start()
|
||||
}))
|
||||
|
||||
mod.AddHandler(session.NewModuleHandler("can.recon off", "",
|
||||
"Stop CAN-bus discovery.",
|
||||
func(args []string) error {
|
||||
return mod.Stop()
|
||||
}))
|
||||
|
||||
mod.AddHandler(session.NewModuleHandler("can.clear", "",
|
||||
"Clear everything collected by the discovery module.",
|
||||
func(args []string) error {
|
||||
mod.Session.CAN.Clear()
|
||||
return nil
|
||||
}))
|
||||
|
||||
mod.AddHandler(session.NewModuleHandler("can.show", "",
|
||||
"Show a list of detected CAN devices.",
|
||||
func(args []string) error {
|
||||
return mod.Show()
|
||||
}))
|
||||
|
||||
return mod
|
||||
}
|
||||
|
||||
func (mod *CANModule) Name() string {
|
||||
return "can"
|
||||
}
|
||||
|
||||
func (mod *CANModule) Description() string {
|
||||
return "A scanner and frames injection module for CAN-bus."
|
||||
}
|
||||
|
||||
func (mod *CANModule) Author() string {
|
||||
return "Simone Margaritelli <evilsocket@gmail.com>"
|
||||
}
|
131
modules/can/can_recon.go
Normal file
131
modules/can/can_recon.go
Normal file
|
@ -0,0 +1,131 @@
|
|||
package can
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
"github.com/evilsocket/islazy/str"
|
||||
"go.einride.tech/can"
|
||||
"go.einride.tech/can/pkg/socketcan"
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
Frame can.Frame
|
||||
Name string
|
||||
Source *network.CANDevice
|
||||
Signals map[string]string
|
||||
}
|
||||
|
||||
func (mod *CANModule) Configure() error {
|
||||
var err error
|
||||
|
||||
if mod.Running() {
|
||||
return session.ErrAlreadyStarted(mod.Name())
|
||||
} else if err, mod.deviceName = mod.StringParam("can.device"); err != nil {
|
||||
return err
|
||||
} else if err, mod.transport = mod.StringParam("can.transport"); err != nil {
|
||||
return err
|
||||
} else if mod.transport != "can" && mod.transport != "udp" {
|
||||
return errors.New("invalid transport")
|
||||
} else if err, mod.dbcPath = mod.StringParam("can.dbc_path"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mod.dbcPath != "" {
|
||||
input, err := os.ReadFile(mod.dbcPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't read %s: %v", mod.dbcPath, err)
|
||||
}
|
||||
|
||||
mod.Info("compiling %s ...", mod.dbcPath)
|
||||
|
||||
result, err := dbcCompile(mod.dbcPath, input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't compile %s: %v", mod.dbcPath, err)
|
||||
}
|
||||
|
||||
for _, warning := range result.Warnings {
|
||||
mod.Warning("%v", warning)
|
||||
}
|
||||
|
||||
mod.dbc = result.Database
|
||||
} else {
|
||||
mod.Warning("no can.dbc_path specified, messages won't be parsed")
|
||||
}
|
||||
|
||||
if mod.conn, err = socketcan.DialContext(context.Background(), mod.transport, mod.deviceName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mod.recv = socketcan.NewReceiver(mod.conn)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mod *CANModule) Start() error {
|
||||
if err := mod.Configure(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return mod.SetRunning(true, func() {
|
||||
mod.Info("started on %s ...", mod.deviceName)
|
||||
|
||||
for mod.recv.Receive() {
|
||||
frame := mod.recv.Frame()
|
||||
msg := Message{
|
||||
Frame: frame,
|
||||
}
|
||||
|
||||
if mod.dbc != nil {
|
||||
if message, found := mod.dbc.Message(frame.ID); found {
|
||||
msg.Name = message.Name
|
||||
|
||||
sourceName := message.SenderNode
|
||||
sourceDesc := ""
|
||||
if sender, found := mod.dbc.Node(message.SenderNode); found {
|
||||
sourceName = sender.Name
|
||||
sourceDesc = sender.Description
|
||||
}
|
||||
|
||||
_, msg.Source = mod.Session.CAN.AddIfNew(sourceName, sourceDesc, frame.Data[:])
|
||||
|
||||
msg.Signals = make(map[string]string)
|
||||
|
||||
for _, signal := range message.Signals {
|
||||
var value string
|
||||
|
||||
if signal.Length <= 32 && signal.IsFloat {
|
||||
value = fmt.Sprintf("%f", signal.UnmarshalFloat(frame.Data))
|
||||
} else if signal.Length == 1 {
|
||||
value = fmt.Sprintf("%v", signal.UnmarshalBool(frame.Data))
|
||||
} else if signal.IsSigned {
|
||||
value = fmt.Sprintf("%d", signal.UnmarshalSigned(frame.Data))
|
||||
} else {
|
||||
value = fmt.Sprintf("%d", signal.UnmarshalUnsigned(frame.Data))
|
||||
}
|
||||
|
||||
msg.Signals[signal.Name] = str.Trim(fmt.Sprintf("%s %s", value, signal.Unit))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod.Session.Events.Add("can.message", msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (mod *CANModule) Stop() error {
|
||||
if mod.conn != nil {
|
||||
mod.recv.Close()
|
||||
mod.conn.Close()
|
||||
mod.conn = nil
|
||||
mod.recv = nil
|
||||
mod.dbc = nil
|
||||
mod.dbcPath = ""
|
||||
}
|
||||
return nil
|
||||
}
|
50
modules/can/can_show.go
Normal file
50
modules/can/can_show.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package can
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/evilsocket/islazy/tui"
|
||||
)
|
||||
|
||||
var (
|
||||
AliveTimeInterval = time.Duration(5) * time.Minute
|
||||
PresentTimeInterval = time.Duration(1) * time.Minute
|
||||
JustJoinedTimeInterval = time.Duration(10) * time.Second
|
||||
)
|
||||
|
||||
func (mod *CANModule) getRow(dev *network.CANDevice) []string {
|
||||
sinceLastSeen := time.Since(dev.LastSeen)
|
||||
seen := dev.LastSeen.Format("15:04:05")
|
||||
|
||||
if sinceLastSeen <= JustJoinedTimeInterval {
|
||||
seen = tui.Bold(seen)
|
||||
} else if sinceLastSeen > PresentTimeInterval {
|
||||
seen = tui.Dim(seen)
|
||||
}
|
||||
|
||||
return []string{
|
||||
dev.Name,
|
||||
dev.Description,
|
||||
humanize.Bytes(dev.Read),
|
||||
seen,
|
||||
}
|
||||
}
|
||||
|
||||
func (mod *CANModule) Show() (err error) {
|
||||
devices := mod.Session.CAN.Devices()
|
||||
|
||||
rows := make([][]string, 0)
|
||||
for _, dev := range devices {
|
||||
rows = append(rows, mod.getRow(dev))
|
||||
}
|
||||
|
||||
tui.Table(mod.Session.Events.Stdout, []string{"Name", "Description", "Data", "Seen"}, rows)
|
||||
|
||||
if len(rows) > 0 {
|
||||
mod.Session.Refresh()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
227
modules/can/dbc.go
Normal file
227
modules/can/dbc.go
Normal file
|
@ -0,0 +1,227 @@
|
|||
package can
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"go.einride.tech/can/pkg/dbc"
|
||||
"go.einride.tech/can/pkg/descriptor"
|
||||
)
|
||||
|
||||
type CompileResult struct {
|
||||
Database *descriptor.Database
|
||||
Warnings []error
|
||||
}
|
||||
|
||||
func dbcCompile(sourceFile string, data []byte) (result *CompileResult, err error) {
|
||||
p := dbc.NewParser(sourceFile, data)
|
||||
if err := p.Parse(); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse DBC source file: %w", err)
|
||||
}
|
||||
defs := p.Defs()
|
||||
c := &compiler{
|
||||
db: &descriptor.Database{SourceFile: sourceFile},
|
||||
defs: defs,
|
||||
}
|
||||
c.collectDescriptors()
|
||||
c.addMetadata()
|
||||
c.sortDescriptors()
|
||||
return &CompileResult{Database: c.db, Warnings: c.warnings}, nil
|
||||
}
|
||||
|
||||
type compileError struct {
|
||||
def dbc.Def
|
||||
reason string
|
||||
}
|
||||
|
||||
func (e *compileError) Error() string {
|
||||
return fmt.Sprintf("failed to compile: %v (%v)", e.reason, e.def)
|
||||
}
|
||||
|
||||
type compiler struct {
|
||||
db *descriptor.Database
|
||||
defs []dbc.Def
|
||||
warnings []error
|
||||
}
|
||||
|
||||
func (c *compiler) addWarning(warning error) {
|
||||
c.warnings = append(c.warnings, warning)
|
||||
}
|
||||
|
||||
func (c *compiler) collectDescriptors() {
|
||||
for _, def := range c.defs {
|
||||
switch def := def.(type) {
|
||||
case *dbc.VersionDef:
|
||||
c.db.Version = def.Version
|
||||
case *dbc.MessageDef:
|
||||
if def.MessageID == dbc.IndependentSignalsMessageID {
|
||||
continue // don't compile
|
||||
}
|
||||
message := &descriptor.Message{
|
||||
Name: string(def.Name),
|
||||
ID: def.MessageID.ToCAN(),
|
||||
IsExtended: def.MessageID.IsExtended(),
|
||||
Length: uint8(def.Size),
|
||||
SenderNode: string(def.Transmitter),
|
||||
}
|
||||
for _, signalDef := range def.Signals {
|
||||
signal := &descriptor.Signal{
|
||||
Name: string(signalDef.Name),
|
||||
IsBigEndian: signalDef.IsBigEndian,
|
||||
IsSigned: signalDef.IsSigned,
|
||||
IsMultiplexer: signalDef.IsMultiplexerSwitch,
|
||||
IsMultiplexed: signalDef.IsMultiplexed,
|
||||
MultiplexerValue: uint(signalDef.MultiplexerSwitch),
|
||||
Start: uint8(signalDef.StartBit),
|
||||
Length: uint8(signalDef.Size),
|
||||
Scale: signalDef.Factor,
|
||||
Offset: signalDef.Offset,
|
||||
Min: signalDef.Minimum,
|
||||
Max: signalDef.Maximum,
|
||||
Unit: signalDef.Unit,
|
||||
}
|
||||
for _, receiver := range signalDef.Receivers {
|
||||
signal.ReceiverNodes = append(signal.ReceiverNodes, string(receiver))
|
||||
}
|
||||
message.Signals = append(message.Signals, signal)
|
||||
}
|
||||
c.db.Messages = append(c.db.Messages, message)
|
||||
case *dbc.NodesDef:
|
||||
for _, node := range def.NodeNames {
|
||||
c.db.Nodes = append(c.db.Nodes, &descriptor.Node{Name: string(node)})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) addMetadata() {
|
||||
for _, def := range c.defs {
|
||||
switch def := def.(type) {
|
||||
case *dbc.SignalValueTypeDef:
|
||||
signal, ok := c.db.Signal(def.MessageID.ToCAN(), string(def.SignalName))
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared signal"})
|
||||
continue
|
||||
}
|
||||
switch def.SignalValueType {
|
||||
case dbc.SignalValueTypeInt:
|
||||
signal.IsFloat = false
|
||||
case dbc.SignalValueTypeFloat32:
|
||||
if signal.Length == 32 {
|
||||
signal.IsFloat = true
|
||||
} else {
|
||||
reason := fmt.Sprintf("incorrect float signal length: %d", signal.Length)
|
||||
c.addWarning(&compileError{def: def, reason: reason})
|
||||
}
|
||||
default:
|
||||
reason := fmt.Sprintf("unsupported signal value type: %v", def.SignalValueType)
|
||||
c.addWarning(&compileError{def: def, reason: reason})
|
||||
}
|
||||
case *dbc.CommentDef:
|
||||
switch def.ObjectType {
|
||||
case dbc.ObjectTypeMessage:
|
||||
if def.MessageID == dbc.IndependentSignalsMessageID {
|
||||
continue // don't compile
|
||||
}
|
||||
message, ok := c.db.Message(def.MessageID.ToCAN())
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared message"})
|
||||
continue
|
||||
}
|
||||
message.Description = def.Comment
|
||||
case dbc.ObjectTypeSignal:
|
||||
if def.MessageID == dbc.IndependentSignalsMessageID {
|
||||
continue // don't compile
|
||||
}
|
||||
signal, ok := c.db.Signal(def.MessageID.ToCAN(), string(def.SignalName))
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared signal"})
|
||||
continue
|
||||
}
|
||||
signal.Description = def.Comment
|
||||
case dbc.ObjectTypeNetworkNode:
|
||||
node, ok := c.db.Node(string(def.NodeName))
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared node"})
|
||||
continue
|
||||
}
|
||||
node.Description = def.Comment
|
||||
}
|
||||
case *dbc.ValueDescriptionsDef:
|
||||
if def.MessageID == dbc.IndependentSignalsMessageID {
|
||||
continue // don't compile
|
||||
}
|
||||
if def.ObjectType != dbc.ObjectTypeSignal {
|
||||
continue // don't compile
|
||||
}
|
||||
signal, ok := c.db.Signal(def.MessageID.ToCAN(), string(def.SignalName))
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared signal"})
|
||||
continue
|
||||
}
|
||||
for _, valueDescription := range def.ValueDescriptions {
|
||||
signal.ValueDescriptions = append(signal.ValueDescriptions, &descriptor.ValueDescription{
|
||||
Description: valueDescription.Description,
|
||||
Value: int64(valueDescription.Value),
|
||||
})
|
||||
}
|
||||
case *dbc.AttributeValueForObjectDef:
|
||||
switch def.ObjectType {
|
||||
case dbc.ObjectTypeMessage:
|
||||
msg, ok := c.db.Message(def.MessageID.ToCAN())
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared message"})
|
||||
continue
|
||||
}
|
||||
switch def.AttributeName {
|
||||
case "GenMsgSendType":
|
||||
if err := msg.SendType.UnmarshalString(def.StringValue); err != nil {
|
||||
c.addWarning(&compileError{def: def, reason: err.Error()})
|
||||
continue
|
||||
}
|
||||
case "GenMsgCycleTime":
|
||||
msg.CycleTime = time.Duration(def.IntValue) * time.Millisecond
|
||||
case "GenMsgDelayTime":
|
||||
msg.DelayTime = time.Duration(def.IntValue) * time.Millisecond
|
||||
}
|
||||
case dbc.ObjectTypeSignal:
|
||||
sig, ok := c.db.Signal(def.MessageID.ToCAN(), string(def.SignalName))
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared signal"})
|
||||
}
|
||||
if def.AttributeName == "GenSigStartValue" {
|
||||
sig.DefaultValue = int(def.IntValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) sortDescriptors() {
|
||||
// Sort nodes by name
|
||||
sort.Slice(c.db.Nodes, func(i, j int) bool {
|
||||
return c.db.Nodes[i].Name < c.db.Nodes[j].Name
|
||||
})
|
||||
// Sort messages by ID
|
||||
sort.Slice(c.db.Messages, func(i, j int) bool {
|
||||
return c.db.Messages[i].ID < c.db.Messages[j].ID
|
||||
})
|
||||
for _, m := range c.db.Messages {
|
||||
m := m
|
||||
// Sort signals by start (and multiplexer value)
|
||||
sort.Slice(m.Signals, func(j, k int) bool {
|
||||
if m.Signals[j].MultiplexerValue < m.Signals[k].MultiplexerValue {
|
||||
return true
|
||||
}
|
||||
return m.Signals[j].Start < m.Signals[k].Start
|
||||
})
|
||||
// Sort value descriptions by value
|
||||
for _, s := range m.Signals {
|
||||
s := s
|
||||
sort.Slice(s.ValueDescriptions, func(k, l int) bool {
|
||||
return s.ValueDescriptions[k].Value < s.ValueDescriptions[l].Value
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
|
@ -120,6 +120,8 @@ func (mod *EventsStream) Render(output io.Writer, e session.Event) {
|
|||
mod.viewBLEEvent(output, e)
|
||||
} else if strings.HasPrefix(e.Tag, "hid.") {
|
||||
mod.viewHIDEvent(output, e)
|
||||
} else if strings.HasPrefix(e.Tag, "can.") {
|
||||
mod.viewCANEvent(output, e)
|
||||
} else if strings.HasPrefix(e.Tag, "gps.") {
|
||||
mod.viewGPSEvent(output, e)
|
||||
} else if strings.HasPrefix(e.Tag, "mod.") {
|
||||
|
|
51
modules/events_stream/events_view_can.go
Normal file
51
modules/events_stream/events_view_can.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package events_stream
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/bettercap/bettercap/modules/can"
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
"github.com/dustin/go-humanize"
|
||||
|
||||
"github.com/evilsocket/islazy/tui"
|
||||
)
|
||||
|
||||
func (mod *EventsStream) viewCANEvent(output io.Writer, e session.Event) {
|
||||
if e.Tag == "can.device.new" {
|
||||
dev := e.Data.(*network.CANDevice)
|
||||
fmt.Fprintf(output, "[%s] [%s] new CAN device %s (%s) detected.\n",
|
||||
e.Time.Format(mod.timeFormat),
|
||||
tui.Green(e.Tag),
|
||||
tui.Bold(dev.Name),
|
||||
tui.Dim(dev.Description))
|
||||
} else if e.Tag == "can.message" {
|
||||
msg := e.Data.(can.Message)
|
||||
|
||||
// unparsed
|
||||
if msg.Name == "" {
|
||||
fmt.Fprintf(output, "[%s] [%s] <id %d> (%s): %s\n",
|
||||
e.Time.Format(mod.timeFormat),
|
||||
tui.Green(e.Tag),
|
||||
msg.Frame.ID,
|
||||
tui.Dim(humanize.Bytes(uint64(msg.Frame.Length))),
|
||||
hex.EncodeToString(msg.Frame.Data[:msg.Frame.Length]))
|
||||
} else {
|
||||
fmt.Fprintf(output, "[%s] [%s] <id %d> %s (%s) from %s:\n",
|
||||
e.Time.Format(mod.timeFormat),
|
||||
tui.Green(e.Tag),
|
||||
msg.Frame.ID,
|
||||
msg.Name,
|
||||
tui.Dim(humanize.Bytes(uint64(msg.Frame.Length))),
|
||||
tui.Bold(msg.Source.Name))
|
||||
|
||||
for name, value := range msg.Signals {
|
||||
fmt.Fprintf(output, " %s : %s\n", name, value)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(output, "[%s] [%s] %v\n", e.Time.Format(mod.timeFormat), tui.Green(e.Tag), e)
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/bettercap/bettercap/modules/arp_spoof"
|
||||
"github.com/bettercap/bettercap/modules/ble"
|
||||
"github.com/bettercap/bettercap/modules/c2"
|
||||
"github.com/bettercap/bettercap/modules/can"
|
||||
"github.com/bettercap/bettercap/modules/caplets"
|
||||
"github.com/bettercap/bettercap/modules/dhcp6_spoof"
|
||||
"github.com/bettercap/bettercap/modules/dns_spoof"
|
||||
|
@ -41,6 +42,7 @@ func LoadModules(sess *session.Session) {
|
|||
sess.Register(arp_spoof.NewArpSpoofer(sess))
|
||||
sess.Register(api_rest.NewRestAPI(sess))
|
||||
sess.Register(ble.NewBLERecon(sess))
|
||||
sess.Register(can.NewCanModule(sess))
|
||||
sess.Register(dhcp6_spoof.NewDHCP6Spoofer(sess))
|
||||
sess.Register(net_recon.NewDiscovery(sess))
|
||||
sess.Register(dns_spoof.NewDNSSpoofer(sess))
|
||||
|
|
110
network/can.go
Normal file
110
network/can.go
Normal file
|
@ -0,0 +1,110 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/evilsocket/islazy/data"
|
||||
)
|
||||
|
||||
type CANDevNewCallback func(dev *CANDevice)
|
||||
type CANDevLostCallback func(dev *CANDevice)
|
||||
|
||||
type CAN struct {
|
||||
sync.RWMutex
|
||||
devices map[string]*CANDevice
|
||||
newCb CANDevNewCallback
|
||||
lostCb CANDevLostCallback
|
||||
}
|
||||
|
||||
type canJSON struct {
|
||||
Devices []*CANDevice `json:"devices"`
|
||||
}
|
||||
|
||||
func NewCAN(aliases *data.UnsortedKV, newcb CANDevNewCallback, lostcb CANDevLostCallback) *CAN {
|
||||
return &CAN{
|
||||
devices: make(map[string]*CANDevice),
|
||||
newCb: newcb,
|
||||
lostCb: lostcb,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *CAN) MarshalJSON() ([]byte, error) {
|
||||
doc := canJSON{
|
||||
Devices: make([]*CANDevice, 0),
|
||||
}
|
||||
|
||||
for _, dev := range h.devices {
|
||||
doc.Devices = append(doc.Devices, dev)
|
||||
}
|
||||
|
||||
return json.Marshal(doc)
|
||||
}
|
||||
|
||||
func (b *CAN) Get(id string) (dev *CANDevice, found bool) {
|
||||
b.RLock()
|
||||
defer b.RUnlock()
|
||||
dev, found = b.devices[id]
|
||||
return
|
||||
}
|
||||
|
||||
func (b *CAN) AddIfNew(name string, description string, payload []byte) (bool, *CANDevice) {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
|
||||
id := name
|
||||
|
||||
if dev, found := b.devices[id]; found {
|
||||
dev.LastSeen = time.Now()
|
||||
dev.AddPayload(payload)
|
||||
return false, dev
|
||||
}
|
||||
|
||||
newDev := NewCANDevice(name, description, payload)
|
||||
b.devices[id] = newDev
|
||||
|
||||
if b.newCb != nil {
|
||||
b.newCb(newDev)
|
||||
}
|
||||
|
||||
return true, newDev
|
||||
}
|
||||
|
||||
func (b *CAN) Remove(id string) {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
|
||||
if dev, found := b.devices[id]; found {
|
||||
delete(b.devices, id)
|
||||
if b.lostCb != nil {
|
||||
b.lostCb(dev)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *CAN) Devices() (devices []*CANDevice) {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
|
||||
devices = make([]*CANDevice, 0)
|
||||
for _, dev := range b.devices {
|
||||
devices = append(devices, dev)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *CAN) EachDevice(cb func(mac string, d *CANDevice)) {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
|
||||
for m, dev := range b.devices {
|
||||
cb(m, dev)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *CAN) Clear() {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
b.devices = make(map[string]*CANDevice)
|
||||
}
|
57
network/can_device.go
Normal file
57
network/can_device.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CANDevice struct {
|
||||
sync.Mutex
|
||||
LastSeen time.Time
|
||||
Name string
|
||||
Description string
|
||||
Read uint64
|
||||
}
|
||||
|
||||
type canDeviceJSON struct {
|
||||
LastSeen time.Time `json:"last_seen"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Read uint64 `json:"description"`
|
||||
}
|
||||
|
||||
func NewCANDevice(name string, description string, payload []byte) *CANDevice {
|
||||
dev := &CANDevice{
|
||||
LastSeen: time.Now(),
|
||||
Name: name,
|
||||
Description: description,
|
||||
Read: uint64(len(payload)),
|
||||
}
|
||||
|
||||
return dev
|
||||
}
|
||||
|
||||
func (dev *CANDevice) MarshalJSON() ([]byte, error) {
|
||||
dev.Lock()
|
||||
defer dev.Unlock()
|
||||
|
||||
doc := canDeviceJSON{
|
||||
LastSeen: dev.LastSeen,
|
||||
Name: dev.Name,
|
||||
Description: dev.Description,
|
||||
Read: dev.Read,
|
||||
}
|
||||
|
||||
return json.Marshal(doc)
|
||||
}
|
||||
|
||||
func (dev *CANDevice) AddPayload(payload []byte) {
|
||||
dev.Lock()
|
||||
defer dev.Unlock()
|
||||
|
||||
sz := len(payload)
|
||||
if payload != nil && sz > 0 {
|
||||
dev.Read += uint64(sz)
|
||||
}
|
||||
}
|
|
@ -76,6 +76,7 @@ type Session struct {
|
|||
WiFi *network.WiFi
|
||||
BLE *network.BLE
|
||||
HID *network.HID
|
||||
CAN *network.CAN
|
||||
Queue *packets.Queue
|
||||
StartedAt time.Time
|
||||
Active bool
|
||||
|
@ -272,6 +273,12 @@ func (s *Session) Start() error {
|
|||
|
||||
s.Firewall = firewall.Make(s.Interface)
|
||||
|
||||
s.CAN = network.NewCAN(s.Aliases, func(dev *network.CANDevice) {
|
||||
s.Events.Add("can.device.new", dev)
|
||||
}, func(dev *network.CANDevice) {
|
||||
s.Events.Add("can.device.lost", dev)
|
||||
})
|
||||
|
||||
s.HID = network.NewHID(s.Aliases, func(dev *network.HIDDevice) {
|
||||
s.Events.Add("hid.device.new", dev)
|
||||
}, func(dev *network.HIDDevice) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue