Skip to content

Commit

Permalink
Add starting table component and refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
NamelessOne91 committed Jul 8, 2024
1 parent 703081c commit 6e599a4
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 69 deletions.
17 changes: 0 additions & 17 deletions cmd/bisturi/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,4 @@ func main() {
if _, err := p.Run(); err != nil {
log.Fatal("Error running program:", err)
}

// // SYS_SOCKET syscall
// rs, err := sockets.NewRawSocket(protocol)
// if err != nil {
// log.Fatalf("Failed to open raw socket: %v", err)
// }
// defer rs.Close()

// // bind the socket to the network interface
// rs.Bind(*networkInterface)
// if err != nil {
// log.Fatalf("Failed to bind socket: %v", err)
// }
// log.Printf("listening for %s packets on interface: %s\n", protocol, networkInterface.Name)

// // SYS_RECVFROM syscall
// rs.ReadPackets()
}
2 changes: 1 addition & 1 deletion protocols/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ func EthFrameFromBytes(raw []byte) (*EthernetFrame, error) {
func (f *EthernetFrame) Info() string {
etv := etherTypesValues[f.etherType]

return fmt.Sprintf("%s Ethernet Frame from MAC %s to MAC %s", f.sourceMAC, f.destinationMAC, etv)
return fmt.Sprintf("%s Ethernet Frame from MAC %s to MAC %s", etv, f.sourceMAC, f.destinationMAC)
}
132 changes: 88 additions & 44 deletions tui/models/bisturi_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package tui
import (
"fmt"
"net"
"strings"

"github.com/NamelessOne91/bisturi/sockets"
"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
Expand All @@ -12,25 +14,23 @@ import (
type step uint8

const (
setupStep step = iota
ifaceStep
protoStep
doneStep
retrieveIfaces step = iota
selectIface
selectProtocol
receivePackets
)

type errMsg struct {
err error
}

func (e errMsg) Error() string { return e.err.Error() }
type errMsg error

type bisturiModel struct {
step step
startMenu startMenuModel
spinner spinner.Model
selectedInterface *net.Interface
startMenu startMenuModel
packetsTable packetsTablemodel
selectedInterface net.Interface
selectedProtocol string
selectedEthType uint16
rawSocket *sockets.RawSocket
err error
}

Expand All @@ -39,74 +39,118 @@ func NewBisturiModel() *bisturiModel {
s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("#00cc99"))

return &bisturiModel{
step: setupStep,
spinner: s,
startMenu: startMenuModel{},
step: retrieveIfaces,
spinner: s,
}
}

func (m bisturiModel) Init() tea.Cmd {
return tea.Sequence(m.spinner.Tick, fetchInterfaces())
return tea.Batch(m.spinner.Tick, fetchInterfaces())
}

func (m *bisturiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
func (m bisturiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch m.step {
case retrieveIfaces:
return m.updateLoading(msg)
case selectIface, selectProtocol:
return m.updateStartMenuSelection(msg)
case receivePackets:
return m.updateReceivingPacket(msg)
default:
return m, nil
}
}

func (m *bisturiModel) updateLoading(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case errMsg:
m.err = msg.err
m.err = msg
return m, tea.Quit

case networkInterfacesMsg:
m.startMenu = newStartMenuModel(msg)
m.step = ifaceStep
m.step = selectIface

return m, nil

case selectedInterfaceMsg:
case tea.KeyMsg:
switch msg.String() {
case "q", "esc", "ctrl+c":
return m, tea.Quit
}
}
var cmd tea.Cmd
m.spinner, cmd = m.spinner.Update(msg)
return m, cmd
}

func (m *bisturiModel) updateStartMenuSelection(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd

m.startMenu, cmd = m.startMenu.Update(msg)

switch msg := msg.(type) {
case selectedIfaceItemMsg:
iface, err := net.InterfaceByName(msg.name)
if err != nil {
return m, func() tea.Msg {
return errMsg{err: err}
}
m.err = err
return m, tea.Quit
}
m.selectedInterface = iface
m.step = protoStep
m.startMenu.step = protoStep
return m, nil
m.selectedInterface = *iface
m.step = selectProtocol

case selectedProtocolMsg:
m.selectedProtocol = msg.protocol
m.selectedEthType = msg.ethTytpe
m.step = doneStep
return m, nil

case tea.KeyMsg:
switch msg.String() {
case "q", "esc", "ctrl+c":
case selectedProtocolItemMsg:
// SYS_SOCKET syscall
rs, err := sockets.NewRawSocket(msg.name, msg.ethType)
if err != nil {
return m, tea.Quit
}
// bind the socket to the network interface
err = rs.Bind(m.selectedInterface)
if err != nil {
m.err = err
return m, tea.Quit
}
m.selectedProtocol = msg.name
m.selectedEthType = msg.ethType
m.rawSocket = rs
m.step = receivePackets
m.packetsTable = newPacketsTable()

case spinner.TickMsg:
m.spinner, cmd = m.spinner.Update(msg)
return m, cmd
return m, nil
}
return m, cmd
}

func (m *bisturiModel) updateReceivingPacket(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd

m.packetsTable, cmd = m.packetsTable.Update(msg)

m.startMenu, cmd = m.startMenu.Update(msg)
return m, cmd
}

func (m bisturiModel) View() string {
if m.err != nil {
if m.rawSocket != nil {
m.rawSocket.Close()
}
return fmt.Sprintf("Error: %s\n", m.err)
}

sb := strings.Builder{}
switch m.step {
case ifaceStep, protoStep:
return m.startMenu.View()
case doneStep:
return fmt.Sprintf("Receiving packet on %s - %s\n", m.selectedInterface.Name, m.selectedProtocol)
case retrieveIfaces:
sb.WriteString(fmt.Sprintf("\n\n %s Retrieving network interfaces...\n\n", m.spinner.View()))
case selectIface, selectProtocol:
sb.WriteString(m.startMenu.View())
case receivePackets:
sb.WriteString(fmt.Sprintf("Receiving %s packets on %s ...\n", m.selectedProtocol, m.selectedInterface.Name))
sb.WriteString(m.packetsTable.View())
default:
return fmt.Sprintf("\n\n %s Retrieving network interfaces...\n\n", m.spinner.View())
sb.WriteString("The program is in an unkowqn state\n")
}

return sb.String()
}
2 changes: 1 addition & 1 deletion tui/models/interfaces_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func fetchInterfaces() tea.Cmd {
return func() tea.Msg {
ifaces, err := net.Interfaces()
if err != nil {
return errMsg{err: err}
return errMsg(err)
}
return networkInterfacesMsg(ifaces)
}
Expand Down
73 changes: 73 additions & 0 deletions tui/models/packets_table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package tui

import (
"strings"

"github.com/NamelessOne91/bisturi/protocols"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/evertras/bubble-table/table"
)

const (
columnKeyProtocol = "protocol"
columnKeyInterface = "interface"
columnKeyInfo = "info"
)

type packetsTablemodel struct {
table table.Model
cachedRows []table.Row
packetsChan <-chan protocols.IPPacket
}

func newPacketsTable() packetsTablemodel {
rows := make([]table.Row, 0, 20)

return packetsTablemodel{
cachedRows: rows,
table: table.New([]table.Column{
table.NewColumn(columnKeyInterface, "Interface", 20),
table.NewColumn(columnKeyProtocol, "Protocol", 20),
table.NewColumn(columnKeyProtocol, "Info", 50),
}).
WithRows(rows).
WithBaseStyle(lipgloss.NewStyle().
BorderForeground(lipgloss.Color("#00cc99")).
Foreground(lipgloss.Color("#00cc99")).
Align(lipgloss.Center),
),
}
}

func (m packetsTablemodel) Init() tea.Cmd {
return nil
}

func (m packetsTablemodel) Update(msg tea.Msg) (packetsTablemodel, tea.Cmd) {
var (
cmd tea.Cmd
cmds []tea.Cmd
)

m.table, cmd = m.table.Update(msg)
cmds = append(cmds, cmd)

switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "esc", "q":
cmds = append(cmds, tea.Quit)
}
}

return m, tea.Batch(cmds...)
}

func (m packetsTablemodel) View() string {
sb := strings.Builder{}

sb.WriteString(m.table.View())

return sb.String()
}
12 changes: 6 additions & 6 deletions tui/models/start_menu.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func newStartMenuModel(interfaces []net.Interface) startMenuModel {
plm := newProtocolsListModel(listWidth, listHeight)

return startMenuModel{
step: ifaceStep,
step: selectIface,
ifaceList: il,
protoList: plm,
}
Expand All @@ -42,10 +42,10 @@ func (m startMenuModel) Init() tea.Cmd {

func (m startMenuModel) Update(msg tea.Msg) (startMenuModel, tea.Cmd) {
switch m.step {
case ifaceStep:
case selectIface:
model, cmd := m.ifaceList.Update(msg)
if i, ok := msg.(selectedIfaceItemMsg); ok {
m.step = protoStep
m.step = selectProtocol
return m, func() tea.Msg {
return selectedInterfaceMsg{
name: i.name,
Expand All @@ -55,7 +55,7 @@ func (m startMenuModel) Update(msg tea.Msg) (startMenuModel, tea.Cmd) {
m.ifaceList = model
return m, cmd

case protoStep:
case selectProtocol:
model, cmd := m.protoList.Update(msg)
if p, ok := msg.(selectedProtocolItemMsg); ok {
return m, func() tea.Msg {
Expand All @@ -74,9 +74,9 @@ func (m startMenuModel) Update(msg tea.Msg) (startMenuModel, tea.Cmd) {
func (m startMenuModel) View() string {
var s string
switch m.step {
case ifaceStep:
case selectIface:
s = m.ifaceList.l.View()
case protoStep:
case selectProtocol:
s = m.protoList.l.View()
default:
return "Unkown step"
Expand Down

0 comments on commit 6e599a4

Please sign in to comment.