diff --git a/.gitignore b/.gitignore index c074bb3..28f274e 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,13 @@ build/windows-custom/NicelandVPN-windows.exe build/darwin-custom/NicelandVPN.app/Contents/MacOS/* build/darwin-custom/NicelandVPN.app/Contents/_CodeSignature/* +cmd/tui/*.exe +cmd/tui/niceland-static-tui +cmd/tui/tui + +cmd/cli/cli +cmd/cli/*.exe + node_modules frontend/dist files diff --git a/cmd/cli/main.go b/cmd/cli/main.go new file mode 100644 index 0000000..d3128e7 --- /dev/null +++ b/cmd/cli/main.go @@ -0,0 +1,139 @@ +package main + +import ( + "fmt" + "log" + "os" + "runtime/debug" + "time" + + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" + "github.com/muesli/termenv" + "github.com/tunnels-is/nicelandvpn-desktop/cmd/termlib" + "github.com/tunnels-is/nicelandvpn-desktop/core" +) + +const ( + VERSION = "1.1.3" + PRODUCTION = true + ENABLE_INSTERFACE = true +) + +var ( + FLAG_COMMAND string + FLAG_USER string + FLAG_PASSWORD string + MONITOR = make(chan int, 200) + TUI *tea.Program + + user *core.User + output = termenv.NewOutput(os.Stdout) + color = output.ForegroundColor() + bgcolor = output.BackgroundColor() + resetString = output.String("... exiting") + + userLoginInputs = make([]textinput.Model, 4) +) + +func main() { + defer func() { + // This will reset the forground and background of the terminal when exiting + resetString.Foreground(color) + resetString.Background(bgcolor) + fmt.Print("\033[H\033[2J") + fmt.Print("\033[H\033[2J") + fmt.Print("\033[H\033[2J") + fmt.Println(resetString) + }() + + core.PRODUCTION = PRODUCTION + core.ENABLE_INSTERFACE = ENABLE_INSTERFACE + core.GLOBAL_STATE.Version = VERSION + + // log.Println(os.Args) + if len(os.Args) < 2 { + os.Exit(1) + } + + switch os.Args[1] { + case "connect": + Connect() + case "getApiKey": + GetAPIKey() + case "createConfig": + CreateDummyConfig() + default: + os.Exit(1) + } + +} + +func GetAPIKey() { + s := termlib.NewSpinner() + go s.Start() + + core.C = new(core.Config) + core.C.DebugLogging = true + core.InitPaths() + core.CreateBaseFolder() + core.InitLogfile() + go core.StartLogQueueProcessor(MONITOR) + err := core.RefreshRouterList() + time.Sleep(2 * time.Second) + s.Stop() + if err != nil { + core.CreateErrorLog("", "Unable to find the best router for your connection: ", err) + os.Exit(1) + } + + fmt.Print("\033[H\033[2J") + termlib.Login(userLoginInputs) + log.Println("USER INPUT:", userLoginInputs[0].Value()) + user = termlib.SendLoginRequest(userLoginInputs) + if user != nil { + log.Println("API KEY:", user.APIKey) + } else { + log.Println("Invalid login..") + } +} + +func CreateDummyConfig() { + +} +func Connect() { + + go core.StartService(MONITOR) + RoutineMonitor() +} + +func RoutineMonitor() { + defer func() { + if r := recover(); r != nil { + core.CreateErrorLog("", r, string(debug.Stack())) + go RoutineMonitor() + } + }() + + for { + select { + default: + time.Sleep(500 * time.Millisecond) + case ID := <-MONITOR: + if ID == 1 { + go core.StateMaintenance(MONITOR) + } else if ID == 2 { + go core.ReadFromRouterSocket(MONITOR) + } else if ID == 3 { + // TUI ONLY .. does not fire on wails GUI + // go TimedUIUpdate(MONITOR) + } else if ID == 4 { + go core.ReadFromLocalSocket(MONITOR) + } else if ID == 6 { + go core.CalculateBandwidth(MONITOR) + } else if ID == 8 { + go core.StartLogQueueProcessor(MONITOR) + } + } + } +} diff --git a/cmd/tui/loginform.go b/cmd/termlib/login.go similarity index 79% rename from cmd/tui/loginform.go rename to cmd/termlib/login.go index 5f5e6b5..9b4824d 100644 --- a/cmd/tui/loginform.go +++ b/cmd/termlib/login.go @@ -1,12 +1,10 @@ -package main +package termlib import ( "encoding/json" "fmt" - "os" "strings" - "github.com/charmbracelet/bubbles/cursor" "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" "github.com/tunnels-is/nicelandvpn-desktop/core" @@ -15,26 +13,25 @@ import ( type loginForm struct { focusIndex int inputs []textinput.Model - cursorMode cursor.Mode } -func intialModel() loginForm { +func intialModel(userInputs []textinput.Model) loginForm { m := loginForm{ - inputs: make([]textinput.Model, 4), + inputs: userInputs, } var t textinput.Model for i := range m.inputs { t = textinput.New() - t.Cursor.Style = cursorStyle + t.Cursor.Style = CursorStyle t.CharLimit = 32 switch i { case 0: t.Placeholder = "Email" t.Focus() - t.PromptStyle = focusedStyle - t.TextStyle = focusedStyle + t.PromptStyle = FocusedStyle + t.TextStyle = FocusedStyle case 1: t.Placeholder = "Password" t.EchoMode = textinput.EchoPassword @@ -60,15 +57,14 @@ func (m loginForm) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.KeyMsg: switch msg.String() { case "ctrl+c": - // core.CleanupOnClose() - sendLoginRequest(m.inputs) // I guess this is one way to exit without going into the TUI + // sendLoginRequest(m.inputs) // I guess this is one way to exit without going into the TUI return m, tea.Quit case "tab", "shift-tab", "enter", "up", "down": s := msg.String() // if hit enter while the submit button was focused if s == "enter" && m.focusIndex == len(m.inputs) { - sendLoginRequest(m.inputs) + // sendLoginRequest(m.inputs) return m, tea.Quit } @@ -87,13 +83,13 @@ func (m loginForm) Update(msg tea.Msg) (tea.Model, tea.Cmd) { for i := 0; i <= len(m.inputs)-1; i++ { if i == m.focusIndex { cmds[i] = m.inputs[i].Focus() - m.inputs[i].PromptStyle = focusedStyle - m.inputs[i].TextStyle = focusedStyle + m.inputs[i].PromptStyle = FocusedStyle + m.inputs[i].TextStyle = FocusedStyle continue } m.inputs[i].Blur() - m.inputs[i].PromptStyle = noStyle - m.inputs[i].TextStyle = noStyle + m.inputs[i].PromptStyle = NoStyle + m.inputs[i].TextStyle = NoStyle } return m, tea.Batch(cmds...) } @@ -122,25 +118,25 @@ func (m loginForm) View() string { } } - button := &blurredButton + button := &BlurredButton if m.focusIndex == len(m.inputs) { - button = &focusedButton + button = &FocusedButton } fmt.Fprintf(&b, "\n\n%s\n\n", *button) return b.String() } -func login() { - _, err := tea.NewProgram(intialModel()).Run() +func Login(userInputs []textinput.Model) { + _, err := tea.NewProgram(intialModel(userInputs)).Run() if err != nil { fmt.Printf("Could not start the login form: %s\n", err) - core.CleanupOnClose() - os.Exit(1) + return } + } -func sendLoginRequest(creds []textinput.Model) { +func SendLoginRequest(creds []textinput.Model) (user *core.User) { var FR core.FORWARD_REQUEST // fill the login form @@ -163,14 +159,17 @@ func sendLoginRequest(creds []textinput.Model) { fmt.Println("\nCode: ", code) fmt.Println("Log in error: ", err) core.CleanupOnClose() - os.Exit(1) + return } + user = new(core.User) // unfold it in the user global err = json.Unmarshal(respBytes, &user) if err != nil { fmt.Println("Response error: ", err) core.CleanupOnClose() - os.Exit(1) + return } + + return } diff --git a/cmd/termlib/spinner.go b/cmd/termlib/spinner.go new file mode 100644 index 0000000..81fbfca --- /dev/null +++ b/cmd/termlib/spinner.go @@ -0,0 +1,78 @@ +package termlib + +import ( + "fmt" + + "github.com/charmbracelet/bubbles/spinner" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +var ( + // Available spinners + spinners = []spinner.Spinner{ + spinner.Line, + spinner.Dot, + spinner.MiniDot, + spinner.Jump, + spinner.Pulse, + spinner.Points, + spinner.Globe, + spinner.Moon, + spinner.Monkey, + } + + textStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("252")).Render + spinnerStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("69")) +) + +type model struct { + spinner spinner.Model + Program *tea.Program +} + +func NewSpinner() (m *model) { + m = new(model) + return m +} + +func (m *model) Start() { + m.ResetSpinner() + m.Program = tea.NewProgram(m) + + if _, err := m.Program.Run(); err != nil { + fmt.Println("could not run program:", err) + } +} + +func (m *model) Stop() { + m.Program.Quit() +} + +func (m model) Init() tea.Cmd { + return m.spinner.Tick +} + +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.QuitMsg: + return m, tea.Quit + case spinner.TickMsg: + var cmd tea.Cmd + m.spinner, cmd = m.spinner.Update(msg) + return m, cmd + default: + return m, nil + } +} + +func (m *model) ResetSpinner() { + m.spinner = spinner.New() + m.spinner.Style = spinnerStyle + m.spinner.Spinner = spinners[6] +} + +func (m model) View() (s string) { + s += fmt.Sprintf("\n %s%s%s\n\n", m.spinner.View(), " ", textStyle("Spinning...")) + return +} diff --git a/cmd/termlib/styles.go b/cmd/termlib/styles.go new file mode 100644 index 0000000..85aab29 --- /dev/null +++ b/cmd/termlib/styles.go @@ -0,0 +1,81 @@ +package termlib + +import ( + "fmt" + + "github.com/charmbracelet/bubbles/table" + "github.com/charmbracelet/lipgloss" +) + +// colors taken from frontend/src/assets/style/variables.scss +var ( + MainBg = lipgloss.Color("#141414") + BodyBg = lipgloss.Color("#202324") + BodyDarkBg = lipgloss.Color("#0A0B0E") + + Teal = lipgloss.Color("#28ad85") + TealBorder = lipgloss.Color("#3AF4BD") + TealHover = lipgloss.Color("#20C997") + + Orange = lipgloss.Color("#FF922D") + OrangeBorder = lipgloss.Color("#EF7503") + OrangeHover = lipgloss.Color("#EF7503") + + LogError = lipgloss.Color("#FF0000") + LogWarning = lipgloss.Color("#FFFF00") + + Lightblue = lipgloss.Color("#20bec9") + Red = lipgloss.Color("#FF5858") + White = lipgloss.Color("#FFFFFF") + Black = lipgloss.Color("#000000") + + SuccessColor = lipgloss.Color("#0AB60A") + ErrorColor = lipgloss.Color("#E70808") +) + +// tab style +var ( + DocStyle = lipgloss.NewStyle().Padding(1, 1, 1, 1) + HighlightColor = TealHover + SelectionColor = Orange + InactiveTabStyle = lipgloss.NewStyle().Border(lipgloss.RoundedBorder(), true, true, false, true).UnsetBorderBottom().BorderForeground(HighlightColor) + ActiveTabStyle = lipgloss.NewStyle().Border(lipgloss.RoundedBorder(), true, true, false, true).UnsetBorderBottom().BorderForeground(HighlightColor).Background(SelectionColor).Foreground(Black) + WindowStyle = lipgloss.NewStyle().BorderForeground(HighlightColor).Padding(0).Border(lipgloss.NormalBorder()) +) + +// generic content style +var BaseStyle = lipgloss.NewStyle(). + BorderStyle(lipgloss.NormalBorder()). + BorderForeground(White). + Padding(0, 1) + +// table style +var TableStyle = table.Styles{ + Header: lipgloss.NewStyle().Padding(0, 1).BorderStyle(lipgloss.NormalBorder()).BorderForeground(Teal).BorderBottom(true).Bold(true).Width(26), + Selected: lipgloss.NewStyle().Foreground(Black).Background(TealBorder).Bold(true), + Cell: lipgloss.NewStyle().Padding(0, 1).Width(26), +} + +// login from styles +var ( + FocusedStyle = lipgloss.NewStyle().Foreground(Orange) + BlurredStyle = lipgloss.NewStyle().Foreground(Teal) + CursorStyle = FocusedStyle.Copy() + NoStyle = lipgloss.NewStyle() + HelpStyle = BlurredStyle.Copy() + CursorModeHelpStyle = lipgloss.NewStyle().Foreground(TealHover) + + FocusedButton = FocusedStyle.Copy().Render("[ Submit ]") + BlurredButton = fmt.Sprintf("[ %s ]", BlurredStyle.Render("Submit")) +) + +// status line +var StatusStyle = lipgloss.NewStyle().Foreground(OrangeHover).Padding(0, 1).Bold(true) +var StatsStyle = lipgloss.NewStyle().Foreground(OrangeHover).Padding(0).Bold(true) + +// Stats table style +var DetailedStatsStyle = table.Styles{ + Header: lipgloss.NewStyle().Padding(0, 1).BorderStyle(lipgloss.NormalBorder()).BorderForeground(Teal).BorderBottom(true).Bold(true).Width(28).Foreground(Teal), + Selected: lipgloss.NewStyle().Foreground(White), + Cell: lipgloss.NewStyle().Padding(0, 1).Width(28), +} diff --git a/cmd/tui/globals.go b/cmd/tui/globals.go index c886237..e626c38 100644 --- a/cmd/tui/globals.go +++ b/cmd/tui/globals.go @@ -1,45 +1,14 @@ package main import ( - "time" - "github.com/tunnels-is/nicelandvpn-desktop/core" - "go.mongodb.org/mongo-driver/bson/primitive" ) var ( - user *User + user *core.User PAFR core.FORWARD_REQUEST ) -// Device token struct need for the login respons from user scruct -type DEVICE_TOKEN struct { - DT string `bson:"DT"` - N string `bson:"N"` - Created time.Time `bson:"C"` -} - -// use struct you get from the login request -type User struct { - ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"` - APIKey string `bson:"AK" json:"APIKey"` - Email string `bson:"E"` - TwoFactorEnabled bool `json:"TwoFactorEnabled" bson:"TFE"` - Disabled bool `bson:"D" json:"Disabled"` - Tokens []*DEVICE_TOKEN `json:"Tokens" bson:"T"` - DeviceToken *DEVICE_TOKEN `json:",omitempty" bson:"-"` - - CashCode int `bson:"CSC" json:"CashCode"` - Affiliate string `bson:"AF"` - SubLevel int `bson:"SUL"` - SubExpiration time.Time `bson:"SE"` - TrialStarted time.Time `bson:"TrialStarted" json:"TrialStarted"` - - CancelSub bool `json:"CancelSub" bson:"CS"` - - Version string `json:"Version" bson:"-"` -} - var ( app_state_str = [10]string{ "VPN List Update", "Ready to Connect", "Version", "VPN Tunnel Ready", diff --git a/cmd/tui/little_helpers.go b/cmd/tui/little_helpers.go index bbc00fb..8623a9e 100644 --- a/cmd/tui/little_helpers.go +++ b/cmd/tui/little_helpers.go @@ -23,7 +23,7 @@ func TimedUIUpdate(MONITOR chan int) { core.GetRoutersAndAccessPoints(&PAFR) } - core.PrepareState() + core.PrepareState() TUI.Send(&tea.KeyMsg{ Type: 0, diff --git a/cmd/tui/main.go b/cmd/tui/main.go index 6a6a535..59a14e6 100644 --- a/cmd/tui/main.go +++ b/cmd/tui/main.go @@ -4,6 +4,7 @@ import ( "runtime/debug" "time" + "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" "github.com/tunnels-is/nicelandvpn-desktop/core" ) @@ -15,8 +16,9 @@ const ( ) var ( - MONITOR = make(chan int, 200) - TUI *tea.Program + MONITOR = make(chan int, 200) + TUI *tea.Program + userLoginInputs = make([]textinput.Model, 4) ) func main() { diff --git a/cmd/tui/styles.go b/cmd/tui/styles.go deleted file mode 100644 index b0eacd6..0000000 --- a/cmd/tui/styles.go +++ /dev/null @@ -1,81 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/charmbracelet/bubbles/table" - "github.com/charmbracelet/lipgloss" -) - -// colors taken from frontend/src/assets/style/variables.scss -var ( - main_bg = lipgloss.Color("#141414") - body_bg = lipgloss.Color("#202324") - body_dark_bg = lipgloss.Color("#0A0B0E") - - teal = lipgloss.Color("#28ad85") - teal_border = lipgloss.Color("#3AF4BD") - teal_hover = lipgloss.Color("#20C997") - - orange = lipgloss.Color("#FF922D") - orange_border = lipgloss.Color("#EF7503") - orange_hover = lipgloss.Color("#EF7503") - - log_error = lipgloss.Color("#FF0000") - log_warning = lipgloss.Color("#FFFF00") - - lightblue = lipgloss.Color("#20bec9") - red = lipgloss.Color("#FF5858") - white = lipgloss.Color("#FFFFFF") - black = lipgloss.Color("#000000") - - success_color = lipgloss.Color("#0AB60A") - error_color = lipgloss.Color("#E70808") -) - -// tab style -var ( - docStyle = lipgloss.NewStyle().Padding(1, 1, 1, 1) - highlightColor = teal_hover - selectionColor = orange - inactiveTabStyle = lipgloss.NewStyle().Border(lipgloss.RoundedBorder(), true, true, false, true).UnsetBorderBottom().BorderForeground(highlightColor) - activeTabStyle = lipgloss.NewStyle().Border(lipgloss.RoundedBorder(), true, true, false, true).UnsetBorderBottom().BorderForeground(highlightColor).Background(selectionColor).Foreground(black) - windowStyle = lipgloss.NewStyle().BorderForeground(highlightColor).Padding(0).Border(lipgloss.NormalBorder()) -) - -// generic content style -var baseStyle = lipgloss.NewStyle(). - BorderStyle(lipgloss.NormalBorder()). - BorderForeground(white). - Padding(0, 1) - -// table style -var table_style = table.Styles{ - Header: lipgloss.NewStyle().Padding(0, 1).BorderStyle(lipgloss.NormalBorder()).BorderForeground(teal).BorderBottom(true).Bold(true).Width(26), - Selected: lipgloss.NewStyle().Foreground(black).Background(teal_border).Bold(true), - Cell: lipgloss.NewStyle().Padding(0, 1).Width(26), -} - -// login from styles -var ( - focusedStyle = lipgloss.NewStyle().Foreground(orange) - blurredStyle = lipgloss.NewStyle().Foreground(teal) - cursorStyle = focusedStyle.Copy() - noStyle = lipgloss.NewStyle() - helpStyle = blurredStyle.Copy() - cursorModeHelpStyle = lipgloss.NewStyle().Foreground(teal_hover) - - focusedButton = focusedStyle.Copy().Render("[ Submit ]") - blurredButton = fmt.Sprintf("[ %s ]", blurredStyle.Render("Submit")) -) - -// status line -var statusStyle = lipgloss.NewStyle().Foreground(orange_hover).Padding(0, 1).Bold(true) -var statsStyle = lipgloss.NewStyle().Foreground(orange_hover).Padding(0).Bold(true) - -// Stats table style -var detailedStatsStyle = table.Styles{ - Header: lipgloss.NewStyle().Padding(0, 1).BorderStyle(lipgloss.NormalBorder()).BorderForeground(teal).BorderBottom(true).Bold(true).Width(28).Foreground(teal), - Selected: lipgloss.NewStyle().Foreground(white), - Cell: lipgloss.NewStyle().Padding(0, 1).Width(28), -} diff --git a/cmd/tui/tui.go b/cmd/tui/tui.go index b29460f..d20afdd 100644 --- a/cmd/tui/tui.go +++ b/cmd/tui/tui.go @@ -13,6 +13,7 @@ import ( "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/tunnels-is/nicelandvpn-desktop/cmd/termlib" "github.com/tunnels-is/nicelandvpn-desktop/core" ) @@ -25,8 +26,6 @@ type model struct { logsViewport viewport.Model stats []table.Model logs []string - ready bool - status []string keys keyMap help help.Model // setting I have no idea how to handle them yet... @@ -182,9 +181,9 @@ func (m model) View() string { isActive := i == m.activeTab if isActive { - style = activeTabStyle.Copy() + style = termlib.ActiveTabStyle.Copy() } else { - style = inactiveTabStyle.Copy() + style = termlib.InactiveTabStyle.Copy() } renderedTabs = append(renderedTabs, style.Render(t)) @@ -199,19 +198,19 @@ func (m model) View() string { var tabContent string switch m.activeTab { case 0: - tabContent = baseStyle.Render(m.serverTable.View()) + tabContent = termlib.BaseStyle.Render(m.serverTable.View()) case 1: - tabContent = baseStyle.Render(m.routerTable.View()) + tabContent = termlib.BaseStyle.Render(m.routerTable.View()) case 2: - tabContent = baseStyle.Render(m.logsViewport.View()) + tabContent = termlib.BaseStyle.Render(m.logsViewport.View()) case 3: // Breaks if terminal columns < 134 ??? Also if for some reason you change the number the form of the stats your will have to change this too tabContent = lipgloss.JoinHorizontal( - lipgloss.Left, baseStyle.Render(lipgloss.JoinVertical(lipgloss.Left, m.stats[0].View(), "\n", m.stats[2].View())), - baseStyle.Render(lipgloss.JoinVertical(lipgloss.Left, m.stats[1].View(), strings.Repeat("\n", 8), m.stats[3].View()))) + lipgloss.Left, termlib.BaseStyle.Render(lipgloss.JoinVertical(lipgloss.Left, m.stats[0].View(), "\n", m.stats[2].View())), + termlib.BaseStyle.Render(lipgloss.JoinVertical(lipgloss.Left, m.stats[1].View(), strings.Repeat("\n", 8), m.stats[3].View()))) default: - tabContent = baseStyle.Render("Not implemented yet!") + tabContent = termlib.BaseStyle.Render("Not implemented yet!") } - doc.WriteString(windowStyle.Render(tabContent)) + doc.WriteString(termlib.WindowStyle.Render(tabContent)) doc.WriteString("\n") // Status line at the bottom @@ -227,12 +226,12 @@ func (m model) View() string { status = lipgloss.JoinHorizontal(lipgloss.Left, status, sep, stats) hlpView := m.help.View(m.keys) if m.help.ShowAll { - doc.WriteString(lipgloss.JoinVertical(lipgloss.Left, statusStyle.Render(status), hlpView)) + doc.WriteString(lipgloss.JoinVertical(lipgloss.Left, termlib.StatusStyle.Render(status), hlpView)) } else { - doc.WriteString(lipgloss.JoinHorizontal(lipgloss.Left, statusStyle.Render(status), sep, hlpView)) + doc.WriteString(lipgloss.JoinHorizontal(lipgloss.Left, termlib.StatusStyle.Render(status), sep, hlpView)) } - return docStyle.Render(doc.String()) + return termlib.DocStyle.Render(doc.String()) } func StartTui() { @@ -240,7 +239,8 @@ func StartTui() { // I do not think I can have 2 completely different models // in bubbletea this is the only way I could figure out // how to do it... - login() + termlib.Login(userLoginInputs) + user = termlib.SendLoginRequest(userLoginInputs) // Initial VPNs and Routers tables // I thought it's a good idea to have the @@ -256,7 +256,7 @@ func StartTui() { } if PAFR.JSONData != nil { - core.GetRoutersAndAccessPoints(&PAFR) + _, _, _ = core.GetRoutersAndAccessPoints(&PAFR) } // Configure tabs and their number @@ -298,13 +298,13 @@ func StartTui() { table.WithColumns(s_col), table.WithRows(s_row), ) - s_t.SetStyles(table_style) + s_t.SetStyles(termlib.TableStyle) r_t := table.New( table.WithColumns(r_col), table.WithRows(r_row), ) - r_t.SetStyles(table_style) + r_t.SetStyles(termlib.TableStyle) detes := detailedStatsInit() // Initial tables finished --- @@ -312,7 +312,7 @@ func StartTui() { // Initialize the viewport for the logs vp := viewport.New(50, 22) vp.SetContent("Loading...") - vp.Style = baseStyle.UnsetBorderStyle() + vp.Style = termlib.BaseStyle.UnsetBorderStyle() // make the model and give some starting values m := model{tabs: tabs, serverTable: s_t, routerTable: r_t, logsViewport: vp, stats: detes} @@ -452,7 +452,7 @@ func detailedStatsInit() []table.Model { table.WithHeight(10), ) - as_t.SetStyles(detailedStatsStyle) + as_t.SetStyles(termlib.DetailedStatsStyle) as_t.Blur() // Interface table @@ -478,7 +478,7 @@ func detailedStatsInit() []table.Model { table.WithHeight(3), ) - i_t.SetStyles(detailedStatsStyle) + i_t.SetStyles(termlib.DetailedStatsStyle) i_t.Blur() // Connection table @@ -504,7 +504,7 @@ func detailedStatsInit() []table.Model { table.WithHeight(3), ) - c_t.SetStyles(detailedStatsStyle) + c_t.SetStyles(termlib.DetailedStatsStyle) c_t.Blur() // Network Stats table @@ -532,7 +532,7 @@ func detailedStatsInit() []table.Model { table.WithHeight(5), ) - n_t.SetStyles(detailedStatsStyle) + n_t.SetStyles(termlib.DetailedStatsStyle) n_t.Blur() return []table.Model{as_t, i_t, c_t, n_t} diff --git a/core/adapter_darwin.go b/core/adapter_darwin.go index ff2bcef..e2834d8 100644 --- a/core/adapter_darwin.go +++ b/core/adapter_darwin.go @@ -30,7 +30,6 @@ func GetIPv6Settings(PotentialDefault *CONNECTION_SETTINGS) { } func GetDnsSettings(PotentialDefault *CONNECTION_SETTINGS) { - dnsout, err := exec.Command("networksetup", "-getdnsservers", PotentialDefault.IFName).Output() if err != nil { CreateErrorLog("", "Unable to find DNS settings >>", err) @@ -55,6 +54,7 @@ func GetDnsSettings(PotentialDefault *CONNECTION_SETTINGS) { func ChangeDNS() { defer RecoverAndLogToFile() } + func ChangeDNSWhileConnected() error { defer RecoverAndLogToFile() return nil @@ -70,7 +70,6 @@ func InitializeTunnelAdapter() error { } func EnablePacketRouting() error { - DisableIPv6() CreateLog("connect", "Creating default route") @@ -120,14 +119,12 @@ func RestoreOriginalDefaultRoute() (err error) { } func RestoreIPv6() { - if !C.DisableIPv6OnConnect { CreateLog("connect", "IPv6 settings unchanged") return } if GLOBAL_STATE.DefaultInterface.IP6Method == "Manual" { - } else if GLOBAL_STATE.DefaultInterface.IP6Method == "Automatic" { _, err := exec.Command("networksetup", "-setv6automatic", GLOBAL_STATE.DefaultInterface.IFName).Output() @@ -144,7 +141,6 @@ func RestoreIPv6() { } func DisableIPv6() { - if !C.DisableIPv6OnConnect { CreateLog("connect", "IPv6 settings unchanged") return @@ -162,8 +158,7 @@ func ResetAfterFailedConnectionAttempt() { RestoreIPv6() } -func RestoreDNS() { - +func RestoreDNS(force false) { } func VerifyAndBackupSettings(PotentialDefault *CONNECTION_SETTINGS) (err error) { @@ -171,7 +166,6 @@ func VerifyAndBackupSettings(PotentialDefault *CONNECTION_SETTINGS) (err error) } func FindDefaultInterfaceAndGateway() (PotentialDefault *CONNECTION_SETTINGS, err error) { - cmd := exec.Command("netstat", "-nr", "-f", "inet") routeList, err := cmd.CombinedOutput() if err != nil { @@ -253,7 +247,6 @@ func FindDefaultInterfaceAndGateway() (PotentialDefault *CONNECTION_SETTINGS, er } func LaunchPreperation() (err error) { - A.Interface, err = water.New(water.Config{ DeviceType: water.TUN, }) @@ -283,9 +276,7 @@ func LaunchPreperation() (err error) { } func SetInterfaceStateToUp(name string) error { - ipOut, err := exec.Command("ifconfig", A.Interface.Name(), "10.4.3.2", "10.4.3.1", "up").Output() - if err != nil { CreateErrorLog("", err, "unable to bring up tunnel adapter ", "STDOUT", string(ipOut)) return err @@ -344,7 +335,6 @@ func DeleteRoute(IP string, ignoreActiveRouterIP bool) (err error) { } func FindDefaultInterfaceAndGatewayDuringStartup() (err error) { - PotentialDefault, err := FindDefaultInterfaceAndGateway() if err != nil { CreateErrorLog("", "Could not find default interface and gateway >> ", err) @@ -373,7 +363,6 @@ func FindDefaultInterfaceAndGatewayDuringStartup() (err error) { } func RestoreSettingsFromFile() { - } func PrintInterfaces() (error, []byte) { @@ -393,7 +382,7 @@ func PrintRouters() (error, []byte) { } func PrintDNS() (error, []byte) { - var out = make([]byte, 0) + out := make([]byte, 0) dnsout, err := exec.Command("networksetup", "-getdnsservers", GLOBAL_STATE.DefaultInterface.IFName).Output() if err != nil { out = append(out, []byte("Error: "+err.Error())...) diff --git a/core/adapter_unix.go b/core/adapter_unix.go index 729655e..179d3de 100644 --- a/core/adapter_unix.go +++ b/core/adapter_unix.go @@ -26,6 +26,7 @@ func (A *Adapter) Close() (err error) { } return } + func (A *Adapter) Uninstall() (err error) { return } @@ -53,7 +54,6 @@ func VerifyAndBackupSettings(PotentialDefault *CONNECTION_SETTINGS) (err error) } func FindDefaultInterfaceAndGatewayDuringStartup() (err error) { - PotentialDefault, err := FindDefaultInterfaceAndGateway() if err != nil { CreateErrorLog("", "Could not find default interface and gateway >> ", err) @@ -122,7 +122,7 @@ func ChangeDNS() error { return nil } -func RestoreDNS() { +func RestoreDNS(force bool) { } func ChangeDNSWhileConnected() error { @@ -156,7 +156,6 @@ func EnablePacketRouting() (err error) { } func InitializeTunnelInterface() (err error) { - err = AdjustRoutersForTunneling() if err != nil { CreateErrorLog("", "Unable to fix route metrics: ", err) @@ -172,7 +171,6 @@ func InitializeTunnelInterface() (err error) { if v.Name == TUNNEL_ADAPTER_NAME { interfaceAlreadyExists = true } - } if !interfaceAlreadyExists { @@ -234,7 +232,6 @@ func SetInterfaceStateToUp() (err error) { } func SetInterfaceStateToDown() (err error) { - ipOut, err := exec.Command("ip", "link", "set", "dev", TUNNEL_ADAPTER_NAME, "down").Output() if err != nil { CreateErrorLog("", "IP || unable to bring the tunnel interface down (link down) || msg: ", err, " || output: ", string(ipOut)) @@ -254,7 +251,7 @@ func AdjustRoutersForTunneling() (err error) { return err } split := strings.Split(string(out), "\n") - var DefaultRoutes = make(map[string]string) + DefaultRoutes := make(map[string]string) for _, v := range split { if strings.Contains(v, "default") { // log.Println(v) @@ -324,7 +321,6 @@ func InitializeTunnelAdapter() (err error) { } func DeleteTunnelInterfaceRoutes(IP string) (err error) { - out, err := exec.Command("ip", "route", "del", IP, "via", TUNNEL_ADAPTER_ADDRESS, "metric", "0").Output() if err != nil { CreateErrorLog("", "IP || Unable to delete route: ", IP, " || Gateway: ", TUNNEL_ADAPTER_ADDRESS, " || msg: ", err, " || output: ", string(out)) @@ -335,7 +331,6 @@ func DeleteTunnelInterfaceRoutes(IP string) (err error) { } func AddRouteToTunnelInterface(IP string) (err error) { - out, err := exec.Command("ip", "route", "add", IP, "via", TUNNEL_ADAPTER_ADDRESS, "metric", "0").Output() if err != nil { @@ -364,7 +359,6 @@ func AddRoute(IP string) (err error) { } func DeleteRoute(IP string, ignoreActiveRouter bool) (err error) { - if GLOBAL_STATE.DefaultInterface == nil { CreateLog("", "Not deleting route, no default interface") return errors.New("no default interface") @@ -386,7 +380,6 @@ func DeleteRoute(IP string, ignoreActiveRouter bool) (err error) { } func FindDefaultInterfaceAndGateway() (POTENTIAL_DEFAULT *CONNECTION_SETTINGS, err error) { - INTERFACE_SETTINGS := FindAllInterfaces() var out []byte @@ -483,7 +476,6 @@ func RestoreIPv6() { } return - } func DisableIPv6() error { diff --git a/core/adapter_windows.go b/core/adapter_windows.go index daf1a9e..bd3abea 100644 --- a/core/adapter_windows.go +++ b/core/adapter_windows.go @@ -249,7 +249,6 @@ func (A *Adapter) Close() (err error) { } func (A *Adapter) Start(cap uint32) (err error) { - r1, _, err1 := syscall.SyscallN(procWintunStartSession.Addr(), uintptr(A.AdapterHandle.handle), uintptr(cap)) if r1 == 0 { err = err1 @@ -408,7 +407,6 @@ func AdapterCleanup(AH *AdapterHandle) { } func initialize_tunnel_adapter() (err error) { - A.Name = TUNNEL_ADAPTER_NAME A.TunHandle = windows.InvalidHandle A.Events = make(chan Event, 10) @@ -427,9 +425,9 @@ func initialize_tunnel_adapter() (err error) { // TRY GENERATING A STATIC UID // A.GUID = new(windows.GUID) - //https://github.com/microsoft/go-winio/blob/main/pkg/guid/guid.go + // https://github.com/microsoft/go-winio/blob/main/pkg/guid/guid.go - //https://github.com/WireGuard/wintun/blob/master/README.md#wintuncreateadapter + // https://github.com/WireGuard/wintun/blob/master/README.md#wintuncreateadapter // A.wt = (*Adapter)(&A.Finalizer) @@ -450,7 +448,7 @@ func initialize_tunnel_adapter() (err error) { CreateLog("", "Starting buffer with 8MB capacity") runtime.SetFinalizer(&A.AdapterHandle, AdapterCleanup) - //0x4000000 + // 0x4000000 err = A.Start(0x4000000) if err != nil { CreateLog("", "Error starting buffer for adapter reader", err) @@ -459,11 +457,12 @@ func initialize_tunnel_adapter() (err error) { return } -var OUTPacket []byte -var OUTErr error +var ( + OUTPacket []byte + OUTErr error +) func VerifyAndBackupSettings(PotentialDefault *CONNECTION_SETTINGS) (err error) { - GetDnsSettings(PotentialDefault) GetIPv6Settings(PotentialDefault) @@ -476,7 +475,6 @@ func VerifyAndBackupSettings(PotentialDefault *CONNECTION_SETTINGS) (err error) } func FindDefaultInterfaceAndGatewayDuringStartup() (err error) { - PotentialDefault, err := FindDefaultInterfaceAndGateway() if err != nil { CreateErrorLog("", "Could not find default interface and gateway >> ", err) @@ -499,7 +497,6 @@ func FindDefaultInterfaceAndGatewayDuringStartup() (err error) { } func GetDnsSettings(PotentialDefault *CONNECTION_SETTINGS) { - cmd := exec.Command("netsh", "interface", "ipv4", "show", "dnsservers", `name=`+PotentialDefault.IFName) cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} out, err := cmd.CombinedOutput() @@ -544,11 +541,9 @@ func GetDnsSettings(PotentialDefault *CONNECTION_SETTINGS) { } } } - } func RestoreSettingsFromFile(PotentialDefault *CONNECTION_SETTINGS) { - CreateLog("", "ADAPTER: ", PotentialDefault) CreateLog("", "RESTORING SETTINGS FROM FILE") @@ -581,9 +576,8 @@ func RestoreSettingsFromFile(PotentialDefault *CONNECTION_SETTINGS) { CreateErrorLog("", "Backup file contained broken DNS") } - RestoreDNS() + RestoreDNS(false) RestoreIPv6() - } func GetIPv6Settings(PotentialDefault *CONNECTION_SETTINGS) { @@ -619,7 +613,6 @@ func GetIPv6Settings(PotentialDefault *CONNECTION_SETTINGS) { CreateLog("", "IPv6 BACKUP: ", PotentialDefault.IFName, " || IPv6: ", true) } } - } func RestoreIPv6() { @@ -646,18 +639,20 @@ func RestoreIPv6() { CreateLog("", "IPv6 Restored on interface: ", GLOBAL_STATE.DefaultInterface.IFName) } - } func ResetAfterFailedConnectionAttempt() { CreateLog("connect", "Connection attempt failed, reseting network configurations") _ = DisableAdapter() RestoreIPv6() - RestoreDNS() + RestoreDNS(false) } -func RestoreDNS() error { +func RestoreDNS(force bool) error { defer RecoverAndLogToFile() + if !C.CustomDNS && !force { + return nil + } if GLOBAL_STATE.DefaultInterface == nil { CreateErrorLog("", "Unable to restore DNS, no interface backup settings found") @@ -736,7 +731,6 @@ func DisableIPv6() error { CreateLog("connect", "Finished disabling IPv6 // time: ", fmt.Sprintf("%.0f", math.Abs(time.Since(start).Seconds())), " seconds") return nil - } func AddRoute(IP string) (err error) { @@ -811,7 +805,6 @@ func DisableAdapter() (err error) { cmd := exec.Command("netsh", "interface", "ipv4", "delete", "address", `name="`+TUNNEL_ADAPTER_NAME+`"`, "addr=", TUNNEL_ADAPTER_ADDRESS, "gateway=", "All") cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} out, err := cmd.Output() - if err != nil { CreateErrorLog("", "Error disabling adapter || msg: ", err, " || output: ", string(out)) return err @@ -845,9 +838,11 @@ func EnablePacketRouting() (err error) { return } - err = ChangeDNS() - if err != nil { - return + if C.CustomDNS { + err = ChangeDNS() + if err != nil { + return + } } return } @@ -898,7 +893,6 @@ func ClearDNS(Interface string) error { } CreateLog("file", "DNS cleared on interface: ", Interface) return nil - } func SetDNS(Interface, IP string, index string) error { @@ -907,7 +901,6 @@ func SetDNS(Interface, IP string, index string) error { cmd := exec.Command("netsh", "interface", "ipv4", "add", "dnsservers", `name=`+Interface, "address="+IP, "index="+index) cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} out, err := cmd.Output() - if err != nil { CreateErrorLog("", "NETSH || Error setting DNS: ", IP, " || interface: ", Interface, " || msg: ", err, " || output: ", string(out)) return err @@ -1051,7 +1044,6 @@ func PrintDNS() ([]byte, error) { // WINDOWS DLL STUFF func CloseAllOpenSockets() error { - if !C.CloseConnectionsOnConnect { CreateLog("", "Leaving open sockets intact") return nil diff --git a/core/api.go b/core/api.go index d09116b..790858a 100644 --- a/core/api.go +++ b/core/api.go @@ -32,7 +32,6 @@ func LocalhostCustomDialer(ctx context.Context, network, addr string) (net.Conn, } func OpenProxyTunnelToRouter(ctx context.Context) (TCP_CONN net.Conn, err error) { - TCP_CONN, err = net.Dial("tcp", GLOBAL_STATE.ActiveRouter.IP+":443") if err != nil { CreateErrorLog("", "Could not dial router: ", GLOBAL_STATE.ActiveRouter.IP, err) @@ -58,7 +57,7 @@ func CleanupWithStateLock() { _ = SetInterfaceStateToDown() RestoreIPv6() - RestoreDNS() + RestoreDNS(false) InstantlyClearPortMaps() SetGlobalStateAsDisconnected() @@ -116,7 +115,6 @@ func SwitchRouter(Tag string) (code int, err error) { } return 200, nil - } func SendRawBytesToLocalhostProxy(method string, route string, data []byte, timeoutMS int) ([]byte, int, error) { @@ -290,7 +288,6 @@ func SendRequestToControllerProxy(method string, route string, data interface{}, var LAST_PRIVATE_ACCESS_POINT_UPDATE = time.Now() func GetPrivateAccessPoints(FR *FORWARD_REQUEST) (interface{}, int, error) { - if GLOBAL_STATE.ActiveRouter == nil { return nil, 500, errors.New("active router not found, please wait a moment") } @@ -299,7 +296,6 @@ func GetPrivateAccessPoints(FR *FORWARD_REQUEST) (interface{}, int, error) { } func LoadRoutersUnAuthenticated() (interface{}, int, error) { - log.Println("GET ROUTERS UN_AHUTH") GLOBAL_STATE.Routers = nil GLOBAL_STATE.Routers = make([]*ROUTER, 0) @@ -387,7 +383,7 @@ func GetRoutersAndAccessPoints(FR *FORWARD_REQUEST) (interface{}, int, error) { PrivateAccessPoints := make([]*AccessPoint, 0) if code == 200 { - CreateLog("", "RESPONSE:", string(responseBytes)) + // CreateLog("", "RESPONSE:", string(responseBytes)) err = json.Unmarshal(responseBytes, &PrivateAccessPoints) if err != nil { CreateErrorLog("", "Unable to unmarshal private device list: ", err) @@ -513,11 +509,9 @@ func GetRoutersAndAccessPoints(FR *FORWARD_REQUEST) (interface{}, int, error) { return false } if GLOBAL_STATE.Routers[a].Score == GLOBAL_STATE.Routers[b].Score { - if GLOBAL_STATE.Routers[a].MS < GLOBAL_STATE.Routers[b].MS { return true } - } return GLOBAL_STATE.Routers[a].Score > GLOBAL_STATE.Routers[b].Score @@ -575,7 +569,6 @@ func GetRoutersAndAccessPoints(FR *FORWARD_REQUEST) (interface{}, int, error) { if GLOBAL_STATE.AccessPoints[a].Router.MS < GLOBAL_STATE.AccessPoints[b].Router.MS { return true } - } return GLOBAL_STATE.AccessPoints[a].Router.Score > GLOBAL_STATE.AccessPoints[b].Router.Score }) @@ -591,7 +584,6 @@ func GetRoutersAndAccessPoints(FR *FORWARD_REQUEST) (interface{}, int, error) { if GLOBAL_STATE.PrivateAccessPoints[a].Router.MS < GLOBAL_STATE.PrivateAccessPoints[b].Router.MS { return true } - } return GLOBAL_STATE.PrivateAccessPoints[a].Router.Score > GLOBAL_STATE.PrivateAccessPoints[b].Router.Score }) @@ -722,6 +714,11 @@ func SetConfig(SF *CONFIG_FORM) error { return errors.New("unable to change config while nicelandVPN is exiting") } + if (C.CustomDNS != SF.CustomDNS) && GLOBAL_STATE.Connected { + CreateLog("loader", "unable to change custom DNS state while connected") + return errors.New("unable to change custom DNS state while connected") + } + if SF.Version != "" { C.Version = SF.Version } @@ -732,6 +729,7 @@ func SetConfig(SF *CONFIG_FORM) error { C.KillSwitch = SF.KillSwitch C.DisableIPv6OnConnect = SF.DisableIPv6OnConnect C.CloseConnectionsOnConnect = SF.CloseConnectionsOnConnect + C.CustomDNS = SF.CustomDNS // if SF.PrevSession != nil { // C.PrevSession = SF.PrevSession @@ -837,7 +835,6 @@ func PrepareState() { // } // } // GLOBAL_STATE.ActiveAccessPoint = GetActiveAccessPointFromActiveSession() - } func GetActiveAccessPointFromActiveSession() *AccessPoint { @@ -1011,10 +1008,9 @@ func ConnectToAccessPoint(NS *CONTROLLER_SESSION_REQUEST, startRouting bool) (S var CCDec []byte CC_DATA := new(OTK_REQUEST) - var FINAL_OTK = new(OTK) - var FINAL_OTKR = new(OTK_REQUEST) + FINAL_OTK := new(OTK) + FINAL_OTKR := new(OTK_REQUEST) defer func() { - if S != nil { S.PrivateKey = nil } diff --git a/core/main.go b/core/main.go index 87725b4..1132d51 100644 --- a/core/main.go +++ b/core/main.go @@ -7,10 +7,10 @@ import ( "errors" "io" "net" + "net/http" "os" "time" - "net/http" _ "net/http/pprof" "github.com/go-ping/ping" @@ -170,7 +170,6 @@ func StateMaintenance(MONITOR chan int) { BUFFER_ERROR = false _ = AutoReconnect() } - } func AutoReconnect() (connected bool) { @@ -258,7 +257,6 @@ func LoadConfig() { var config *os.File var err error defer func() { - if config != nil { _ = config.Close() } @@ -289,6 +287,8 @@ func LoadConfig() { NC.AutoReconnect = true NC.KillSwitch = false NC.DisableIPv6OnConnect = true + NC.LogBlockedDomains = true + NC.CustomDNS = false var cb []byte cb, err = json.Marshal(NC) @@ -305,7 +305,7 @@ func LoadConfig() { return } - err = os.Chmod(GLOBAL_STATE.ConfigPath, 0777) + err = os.Chmod(GLOBAL_STATE.ConfigPath, 0o777) if err != nil { GLOBAL_STATE.ClientStartupError = true CreateErrorLog("", "Unable to change ownership of log file: ", err) @@ -353,7 +353,7 @@ func LoadDNSWhitelist() (err error) { return nil } - WFile, err := os.OpenFile(C.DomainWhitelist, os.O_RDWR|os.O_CREATE, 0777) + WFile, err := os.OpenFile(C.DomainWhitelist, os.O_RDWR|os.O_CREATE, 0o777) if err != nil { return err } @@ -494,7 +494,6 @@ func ParseRoutersFromRawDataToMemory(lines [][]byte) (count int) { } return - } func DownloadRoutersFromOnlineSource() ([][]byte, error) { @@ -657,14 +656,13 @@ func BackupSettingsToFile(NewDefault *CONNECTION_SETTINGS) { return } - err = os.Chmod(GLOBAL_STATE.LogFileName, 0777) + err = os.Chmod(GLOBAL_STATE.LogFileName, 0o777) if err != nil { CreateErrorLog("", "Unable to change ownership of log file: ", err) return } defer func() { - if backupFile != nil { _ = backupFile.Close() } @@ -682,7 +680,6 @@ func BackupSettingsToFile(NewDefault *CONNECTION_SETTINGS) { CreateErrorLog("", "Unable to write backup settings to file: ", err) return } - } func InterfaceMaintenenceAndBackup() { diff --git a/core/packet.go b/core/packet.go index 06c125b..7ba4a37 100644 --- a/core/packet.go +++ b/core/packet.go @@ -1,510 +1,509 @@ -package core - -import ( - "encoding/binary" - "net" - - "github.com/miekg/dns" -) - -var ( - PREV_DNS_IP [4]byte - IS_UNIX bool = false -) - -var ( - EP_Version byte - EP_Protocol byte - - EP_DstIP [4]byte - - EP_IPv4HeaderLength byte - EP_IPv4Header []byte - EP_TPHeader []byte - - EP_SrcPort [2]byte - EP_DstPort [2]byte - EP_MappedPort *RP - - EP_NAT_IP [4]byte - EP_NAT_OK bool - - EP_RST byte - - EP_DNS_Response []byte - EP_DNS_OK bool - EP_DNS_Port_Placeholder [2]byte - EP_DNS_Packet []byte - - // This IP gets over-written on connect - EP_VPNSrcIP [4]byte -) - -func ProcessEgressPacket(p *[]byte) (sendRemote bool, sendLocal bool) { - - packet := *p - - EP_Version = packet[0] >> 4 - if EP_Version != 4 { - return false, false - } - - EP_Protocol = packet[9] - if EP_Protocol != 6 && EP_Protocol != 17 { - return false, false - } - - // Get the full IPv4Header length in bytes - EP_IPv4HeaderLength = (packet[0] << 4 >> 4) * 32 / 8 - - EP_IPv4Header = packet[:EP_IPv4HeaderLength] - EP_TPHeader = packet[EP_IPv4HeaderLength:] - - // DROP RST packets - if EP_Protocol == 6 { - EP_RST = EP_TPHeader[13] & 0x7 >> 2 - // fmt.Printf("%08b - RST:%08b\n", EP_TPHeader[13], EP_RST) - if EP_RST == 1 { - // log.Println("RST PACKET") - return false, false - } - } - - EP_DstIP[0] = packet[16] - EP_DstIP[1] = packet[17] - EP_DstIP[2] = packet[18] - EP_DstIP[3] = packet[19] - - // This drops NETBIOS DNS packets to the VPN interface - if EP_DstIP == [4]byte{10, 4, 3, 255} { - return false, false - } - - EP_SrcPort[0] = EP_TPHeader[0] - EP_SrcPort[1] = EP_TPHeader[1] - - EP_DstPort[0] = EP_TPHeader[2] - EP_DstPort[1] = EP_TPHeader[3] - - // CUSTOM DNS - // https://stackoverflow.com/questions/7565300/identifying-dns-packets - if EP_Protocol == 17 { - if IsDNSQuery(EP_TPHeader[8:]) { - // log.Println("DNS FOUND!!!!!!") - - // log.Println("UDP HEADER:", EP_TPHeader[:8]) - // log.Println("UDP DATA:", EP_TPHeader[8:]) - // log.Println("UDP HEADER:", EP_TPHeader[:8], EP_DstIP, EP_DstPort) - EP_DNS_Response, EP_DNS_OK = ProcessEgressDNSQuery(EP_TPHeader[8:]) - if EP_DNS_OK { - // Replace Source IP - EP_IPv4Header[12] = EP_IPv4Header[16] - EP_IPv4Header[13] = EP_IPv4Header[17] - EP_IPv4Header[14] = EP_IPv4Header[18] - EP_IPv4Header[15] = EP_IPv4Header[19] - - // Replace Destination IP - EP_IPv4Header[16] = IP_InterfaceIP[0] - EP_IPv4Header[17] = IP_InterfaceIP[1] - EP_IPv4Header[18] = IP_InterfaceIP[2] - EP_IPv4Header[19] = IP_InterfaceIP[3] - - // Replace Source Port - EP_DNS_Port_Placeholder[0] = EP_TPHeader[0] - EP_DNS_Port_Placeholder[1] = EP_TPHeader[1] - - EP_TPHeader[0] = EP_TPHeader[2] - EP_TPHeader[1] = EP_TPHeader[3] - - EP_TPHeader[2] = EP_DNS_Port_Placeholder[0] - EP_TPHeader[3] = EP_DNS_Port_Placeholder[1] - - /// - EP_DNS_Packet = append(packet[:EP_IPv4HeaderLength+8], EP_DNS_Response...) - // Modify the total Length of the IP Header - binary.BigEndian.PutUint16(EP_DNS_Packet[2:4], uint16(int(EP_IPv4HeaderLength)+8+len(EP_DNS_Response))) - - // Modify the length of the Transport Header - binary.BigEndian.PutUint16(EP_DNS_Packet[EP_IPv4HeaderLength+4:EP_IPv4HeaderLength+6], uint16(len(EP_DNS_Response))+8) - - RecalculateAndReplaceIPv4HeaderChecksum(EP_DNS_Packet[:EP_IPv4HeaderLength]) - RecalculateAndReplaceTransportChecksum(EP_DNS_Packet[:EP_IPv4HeaderLength], EP_DNS_Packet[EP_IPv4HeaderLength:]) - - *p = EP_DNS_Packet - - return false, true - } else { - - if IS_UNIX { - PREV_DNS_IP[0] = EP_IPv4Header[16] - PREV_DNS_IP[1] = EP_IPv4Header[17] - PREV_DNS_IP[2] = EP_IPv4Header[18] - PREV_DNS_IP[3] = EP_IPv4Header[19] - - EP_IPv4Header[16] = C.DNS1Bytes[0] - EP_IPv4Header[17] = C.DNS1Bytes[1] - EP_IPv4Header[18] = C.DNS1Bytes[2] - EP_IPv4Header[19] = C.DNS1Bytes[3] - } - - } - - } - } - - if EP_Protocol == 6 { - - EP_MappedPort = CreateOrGetPortMapping(&TCP_o0, EP_DstIP, EP_SrcPort, EP_DstPort) - if EP_MappedPort == nil { - // log.Println("NO TCP PORT MAPPING", EP_DstIP, EP_SrcPort, EP_DstPort) - return false, false - } - - } else if EP_Protocol == 17 { - - EP_MappedPort = CreateOrGetPortMapping(&UDP_o0, EP_DstIP, EP_SrcPort, EP_DstPort) - if EP_MappedPort == nil { - // log.Println("NO UDP PORT MAPPING", EP_DstIP, EP_SrcPort, EP_DstPort) - return false, false - } - - } - - EP_NAT_IP, EP_NAT_OK = AS.AP.NAT_CACHE[EP_DstIP] - if EP_NAT_OK { - // log.Println("FOUND NAT", EP_DstIP, EP_NAT_IP) - EP_IPv4Header[16] = EP_NAT_IP[0] - EP_IPv4Header[17] = EP_NAT_IP[1] - EP_IPv4Header[18] = EP_NAT_IP[2] - EP_IPv4Header[19] = EP_NAT_IP[3] - } - - EP_TPHeader[0] = EP_MappedPort.Mapped[0] - EP_TPHeader[1] = EP_MappedPort.Mapped[1] - - EP_IPv4Header[12] = EP_VPNSrcIP[0] - EP_IPv4Header[13] = EP_VPNSrcIP[1] - EP_IPv4Header[14] = EP_VPNSrcIP[2] - EP_IPv4Header[15] = EP_VPNSrcIP[3] - - RecalculateAndReplaceIPv4HeaderChecksum(EP_IPv4Header) - RecalculateAndReplaceTransportChecksum(EP_IPv4Header, EP_TPHeader) - - return true, false -} - -var ( - IP_Version byte - IP_Protocol byte - - IP_DstIP [4]byte - IP_SrcIP [4]byte - - IP_IPv4HeaderLength byte - IP_IPv4Header []byte - IP_TPHeader []byte - - IP_SrcPort [2]byte - IP_DstPort [2]byte - IP_MappedPort *RP - - IP_NAT_IP [4]byte - IP_NAT_OK bool - - // This IP gets over-written on connect - // IP_VPNSrcIP [4]byte - IP_InterfaceIP [4]byte -) - -func ProcessIngressPacket(packet []byte) bool { - - IP_SrcIP[0] = packet[12] - IP_SrcIP[1] = packet[13] - IP_SrcIP[2] = packet[14] - IP_SrcIP[3] = packet[15] - - IP_Protocol = packet[9] - - IP_IPv4HeaderLength = (packet[0] << 4 >> 4) * 32 / 8 - IP_IPv4Header = packet[:IP_IPv4HeaderLength] - IP_TPHeader = packet[IP_IPv4HeaderLength:] - - IP_DstPort[0] = IP_TPHeader[2] - IP_DstPort[1] = IP_TPHeader[3] - - IP_NAT_IP, IP_NAT_OK = AS.AP.REVERSE_NAT_CACHE[IP_SrcIP] - if IP_NAT_OK { - // log.Println("FOUND INGRESS NAT", IP_SrcIP, IP_NAT_IP) - IP_IPv4Header[12] = IP_NAT_IP[0] - IP_IPv4Header[13] = IP_NAT_IP[1] - IP_IPv4Header[14] = IP_NAT_IP[2] - IP_IPv4Header[15] = IP_NAT_IP[3] - - IP_SrcIP[0] = IP_NAT_IP[0] - IP_SrcIP[1] = IP_NAT_IP[1] - IP_SrcIP[2] = IP_NAT_IP[2] - IP_SrcIP[3] = IP_NAT_IP[3] - } - - if IP_Protocol == 6 { - - IP_MappedPort = GetIngressPortMapping(&TCP_o0, IP_SrcIP, IP_DstPort) - if IP_MappedPort == nil { - // log.Println("NO PORT MAPPING", IP_SrcIP, binary.BigEndian.Uint16(IP_DstPort[:])) - return false - } - - } else if IP_Protocol == 17 { - - IP_MappedPort = GetIngressPortMapping(&UDP_o0, IP_SrcIP, IP_DstPort) - if IP_MappedPort == nil { - // log.Println("NO PORT MAPPING", IP_SrcIP, binary.BigEndian.Uint16(IP_DstPort[:])) - return false - } - - } - - IP_TPHeader[2] = IP_MappedPort.Local[0] - IP_TPHeader[3] = IP_MappedPort.Local[1] - - IP_IPv4Header[16] = IP_InterfaceIP[0] - IP_IPv4Header[17] = IP_InterfaceIP[1] - IP_IPv4Header[18] = IP_InterfaceIP[2] - IP_IPv4Header[19] = IP_InterfaceIP[3] - - if EP_Protocol == 17 { - if IP_SrcIP == C.DNS1Bytes && IS_UNIX { - // if IsDNSQuery(EP_TPHeader[8:]) && IS_UNIX { - IP_IPv4Header[12] = PREV_DNS_IP[0] - IP_IPv4Header[13] = PREV_DNS_IP[1] - IP_IPv4Header[14] = PREV_DNS_IP[2] - IP_IPv4Header[15] = PREV_DNS_IP[3] - } - } - - RecalculateAndReplaceIPv4HeaderChecksum(IP_IPv4Header) - RecalculateAndReplaceTransportChecksum(IP_IPv4Header, IP_TPHeader) - - return true -} - -func IsDNSQuery(UDPData []byte) bool { - - if len(UDPData) < 12 { - // log.Println("NOT ENOUGH UDP DATA") - return false - } - - // QR == 0 when making a DNS Query - QR := UDPData[2] >> 7 - if QR != 0 { - return false - } - - // AN Count is always 0 for queries - if UDPData[6] != 0 || UDPData[7] != 0 { - // log.Println("AN COUNT OFF", UDPData[6:8]) - return false - } - - // NS Count is always 0 for queries - if UDPData[8] != 0 || UDPData[9] != 0 { - // log.Println("NS COUNT OFF", UDPData[8:10]) - return false - } - - return true -} -func ProcessEgressDNSQuery(UDPData []byte) (DNSResponse []byte, shouldProcess bool) { - - q := new(dns.Msg) - q.Unpack(UDPData) - - x := new(dns.Msg) - x.SetReply(q) - x.Authoritative = true - x.Compress = true - - isCustomDNS := false - for i := range x.Question { - - if x.Question[i].Qtype == dns.TypeA { - domain := x.Question[i].Name[0 : len(x.Question[i].Name)-1] - - _, ok := GLOBAL_BLOCK_LIST[domain] - // CreateLog("", "DNS Q: ", domain, len(GLOBAL_BLOCK_LIST), ok) - if ok { - - CreateLog("", "Domain blocked:", domain) - isCustomDNS = true - x.Answer = append(x.Answer, &dns.A{ - Hdr: dns.RR_Header{ - Class: dns.TypeA, - Rrtype: dns.ClassINET, - Name: x.Question[i].Name, - Ttl: 5, - }, - A: net.ParseIP("127.0.0.1"), - }) - - } else { - - IPS, CNAME := DNSAMapping(domain) - if CNAME != "" { - - isCustomDNS = true - x.Answer = append(x.Answer, &dns.CNAME{ - Hdr: dns.RR_Header{ - Class: dns.ClassNONE, - Rrtype: dns.TypeCNAME, - Name: x.Question[i].Name, - Ttl: 5, - }, - Target: CNAME + ".", - }) - - } else if IPS != nil { - isCustomDNS = true - - for ii := range IPS { - x.Answer = append(x.Answer, &dns.A{ - Hdr: dns.RR_Header{ - Class: dns.TypeA, - Rrtype: dns.ClassINET, - Name: x.Question[i].Name, - Ttl: 5, - }, - A: IPS[ii].To4(), - }) - } - } - - } - - } else if x.Question[i].Qtype == dns.TypeTXT { - - TXTS := DNSTXTMapping(x.Question[i].Name[0 : len(x.Question[i].Name)-1]) - if TXTS != nil { - isCustomDNS = true - for ii := range TXTS { - x.Answer = append(x.Answer, &dns.TXT{ - Hdr: dns.RR_Header{ - Class: dns.ClassNONE, - Rrtype: dns.TypeTXT, - Name: x.Question[i].Name, - Ttl: 30, - }, - Txt: []string{TXTS[ii]}, - }) - } - } - - } else if x.Question[i].Qtype == dns.TypeCNAME { - - CNAME := DNSCNameMapping(x.Question[i].Name[0 : len(x.Question[i].Name)-1]) - if CNAME != "" { - isCustomDNS = true - x.Answer = append(x.Answer, &dns.CNAME{ - Hdr: dns.RR_Header{ - Class: dns.ClassNONE, - Rrtype: dns.TypeCNAME, - Name: x.Question[i].Name, - Ttl: 30, - }, - Target: CNAME + ".", - }) - } - - } - - } - - if isCustomDNS { - - var err error - DNSResponse, err = x.Pack() - if err != nil { - // log.Println("UNABLE TO PICK DNS RESPONSE: ", err) - return - } - - shouldProcess = true - return - } - - return -} - -func ProcessIngressDNSQuery(TPHeader []byte) bool { - - return true -} - -func RecalculateAndReplaceIPv4HeaderChecksum(bytes []byte) { - // Clear checksum bytes - bytes[10] = 0 - bytes[11] = 0 - - // Compute checksum - var csum uint32 - for i := 0; i < len(bytes); i += 2 { - csum += uint32(bytes[i]) << 8 - csum += uint32(bytes[i+1]) - } - for { - // Break when sum is less or equals to 0xFFFF - if csum <= 65535 { - break - } - // Add carry to the sum - csum = (csum >> 16) + uint32(uint16(csum)) - } - - // Flip all the bits and replace checksum - binary.BigEndian.PutUint16(bytes[10:12], ^uint16(csum)) - return -} - -func RecalculateAndReplaceTransportChecksum(IPv4Header []byte, TPPacket []byte) { - - if IPv4Header[9] == 6 { - TPPacket[16] = 0 - TPPacket[17] = 0 - } else if IPv4Header[9] == 17 { - TPPacket[6] = 0 - TPPacket[7] = 0 - } - - var csum uint32 - csum += (uint32(IPv4Header[12]) + uint32(IPv4Header[14])) << 8 - csum += uint32(IPv4Header[13]) + uint32(IPv4Header[15]) - csum += (uint32(IPv4Header[16]) + uint32(IPv4Header[18])) << 8 - csum += uint32(IPv4Header[17]) + uint32(IPv4Header[19]) - csum += uint32(uint8(IPv4Header[9])) - tcpLength := uint32(len(TPPacket)) - - csum += tcpLength & 0xffff - csum += tcpLength >> 16 - - length := len(TPPacket) - 1 - for i := 0; i < length; i += 2 { - // For our test packet, doing this manually is about 25% faster - // (740 ns vs. 1000ns) than doing it by calling binary.BigEndian.Uint16. - csum += uint32(TPPacket[i]) << 8 - csum += uint32(TPPacket[i+1]) - } - if len(TPPacket)%2 == 1 { - csum += uint32(TPPacket[length]) << 8 - } - for csum > 0xffff { - csum = (csum >> 16) + (csum & 0xffff) - } - - if IPv4Header[9] == 6 { - binary.BigEndian.PutUint16(TPPacket[16:18], ^uint16(csum)) - } else if IPv4Header[9] == 17 { - binary.BigEndian.PutUint16(TPPacket[6:8], ^uint16(csum)) - } - - return -} +package core + +import ( + "encoding/binary" + "net" + + "github.com/miekg/dns" +) + +var ( + PREV_DNS_IP [4]byte + IS_UNIX bool = false +) + +var ( + EP_Version byte + EP_Protocol byte + + EP_DstIP [4]byte + + EP_IPv4HeaderLength byte + EP_IPv4Header []byte + EP_TPHeader []byte + + EP_SrcPort [2]byte + EP_DstPort [2]byte + EP_MappedPort *RP + + EP_NAT_IP [4]byte + EP_NAT_OK bool + + EP_RST byte + + EP_DNS_Response []byte + EP_DNS_OK bool + EP_DNS_Port_Placeholder [2]byte + EP_DNS_Packet []byte + + // This IP gets over-written on connect + EP_VPNSrcIP [4]byte + + EP_NEW_RST int +) + +func ProcessEgressPacket(p *[]byte) (sendRemote bool, sendLocal bool) { + packet := *p + + EP_Version = packet[0] >> 4 + if EP_Version != 4 { + return false, false + } + + EP_Protocol = packet[9] + if EP_Protocol != 6 && EP_Protocol != 17 { + return false, false + } + + // Get the full IPv4Header length in bytes + EP_IPv4HeaderLength = (packet[0] << 4 >> 4) * 32 / 8 + + EP_IPv4Header = packet[:EP_IPv4HeaderLength] + EP_TPHeader = packet[EP_IPv4HeaderLength:] + + // DROP RST packets + if EP_Protocol == 6 { + EP_RST = EP_TPHeader[13] & 0x7 >> 2 + if EP_RST == 1 { + EP_NEW_RST = int(EP_TPHeader[13]) + EP_NEW_RST |= int(0b00010100) + EP_TPHeader[13] = byte(EP_NEW_RST) + // fmt.Printf("%08b - RST:%08b\n", EP_TPHeader[13], EP_RST) + // fmt.Printf("POST TRANSFORM: %08b\n", EP_TPHeader[13]) + // log.Println("RST PACKET") + // return false, false + } + } + + EP_DstIP[0] = packet[16] + EP_DstIP[1] = packet[17] + EP_DstIP[2] = packet[18] + EP_DstIP[3] = packet[19] + + // This drops NETBIOS DNS packets to the VPN interface + if EP_DstIP == [4]byte{10, 4, 3, 255} { + return false, false + } + + EP_SrcPort[0] = EP_TPHeader[0] + EP_SrcPort[1] = EP_TPHeader[1] + + EP_DstPort[0] = EP_TPHeader[2] + EP_DstPort[1] = EP_TPHeader[3] + + // CUSTOM DNS + // https://stackoverflow.com/questions/7565300/identifying-dns-packets + if EP_Protocol == 17 { + if IsDNSQuery(EP_TPHeader[8:]) { + // log.Println("DNS FOUND!!!!!!") + + // log.Println("UDP HEADER:", EP_TPHeader[:8]) + // log.Println("UDP DATA:", EP_TPHeader[8:]) + // log.Println("UDP HEADER:", EP_TPHeader[:8], EP_DstIP, EP_DstPort) + EP_DNS_Response, EP_DNS_OK = ProcessEgressDNSQuery(EP_TPHeader[8:]) + if EP_DNS_OK { + // Replace Source IP + EP_IPv4Header[12] = EP_IPv4Header[16] + EP_IPv4Header[13] = EP_IPv4Header[17] + EP_IPv4Header[14] = EP_IPv4Header[18] + EP_IPv4Header[15] = EP_IPv4Header[19] + + // Replace Destination IP + EP_IPv4Header[16] = IP_InterfaceIP[0] + EP_IPv4Header[17] = IP_InterfaceIP[1] + EP_IPv4Header[18] = IP_InterfaceIP[2] + EP_IPv4Header[19] = IP_InterfaceIP[3] + + // Replace Source Port + EP_DNS_Port_Placeholder[0] = EP_TPHeader[0] + EP_DNS_Port_Placeholder[1] = EP_TPHeader[1] + + EP_TPHeader[0] = EP_TPHeader[2] + EP_TPHeader[1] = EP_TPHeader[3] + + EP_TPHeader[2] = EP_DNS_Port_Placeholder[0] + EP_TPHeader[3] = EP_DNS_Port_Placeholder[1] + + /// + EP_DNS_Packet = append(packet[:EP_IPv4HeaderLength+8], EP_DNS_Response...) + // Modify the total Length of the IP Header + binary.BigEndian.PutUint16(EP_DNS_Packet[2:4], uint16(int(EP_IPv4HeaderLength)+8+len(EP_DNS_Response))) + + // Modify the length of the Transport Header + binary.BigEndian.PutUint16(EP_DNS_Packet[EP_IPv4HeaderLength+4:EP_IPv4HeaderLength+6], uint16(len(EP_DNS_Response))+8) + + RecalculateAndReplaceIPv4HeaderChecksum(EP_DNS_Packet[:EP_IPv4HeaderLength]) + RecalculateAndReplaceTransportChecksum(EP_DNS_Packet[:EP_IPv4HeaderLength], EP_DNS_Packet[EP_IPv4HeaderLength:]) + + *p = EP_DNS_Packet + + return false, true + } else { + if IS_UNIX { + PREV_DNS_IP[0] = EP_IPv4Header[16] + PREV_DNS_IP[1] = EP_IPv4Header[17] + PREV_DNS_IP[2] = EP_IPv4Header[18] + PREV_DNS_IP[3] = EP_IPv4Header[19] + + EP_IPv4Header[16] = C.DNS1Bytes[0] + EP_IPv4Header[17] = C.DNS1Bytes[1] + EP_IPv4Header[18] = C.DNS1Bytes[2] + EP_IPv4Header[19] = C.DNS1Bytes[3] + } + } + + } + } + + if EP_Protocol == 6 { + + EP_MappedPort = CreateOrGetPortMapping(&TCP_o0, EP_DstIP, EP_SrcPort, EP_DstPort) + if EP_MappedPort == nil { + // log.Println("NO TCP PORT MAPPING", EP_DstIP, EP_SrcPort, EP_DstPort) + return false, false + } + + } else if EP_Protocol == 17 { + + EP_MappedPort = CreateOrGetPortMapping(&UDP_o0, EP_DstIP, EP_SrcPort, EP_DstPort) + if EP_MappedPort == nil { + // log.Println("NO UDP PORT MAPPING", EP_DstIP, EP_SrcPort, EP_DstPort) + return false, false + } + + } + + EP_NAT_IP, EP_NAT_OK = AS.AP.NAT_CACHE[EP_DstIP] + if EP_NAT_OK { + // log.Println("FOUND NAT", EP_DstIP, EP_NAT_IP) + EP_IPv4Header[16] = EP_NAT_IP[0] + EP_IPv4Header[17] = EP_NAT_IP[1] + EP_IPv4Header[18] = EP_NAT_IP[2] + EP_IPv4Header[19] = EP_NAT_IP[3] + } + + EP_TPHeader[0] = EP_MappedPort.Mapped[0] + EP_TPHeader[1] = EP_MappedPort.Mapped[1] + + EP_IPv4Header[12] = EP_VPNSrcIP[0] + EP_IPv4Header[13] = EP_VPNSrcIP[1] + EP_IPv4Header[14] = EP_VPNSrcIP[2] + EP_IPv4Header[15] = EP_VPNSrcIP[3] + + RecalculateAndReplaceIPv4HeaderChecksum(EP_IPv4Header) + RecalculateAndReplaceTransportChecksum(EP_IPv4Header, EP_TPHeader) + + return true, false +} + +var ( + IP_Version byte + IP_Protocol byte + + IP_DstIP [4]byte + IP_SrcIP [4]byte + + IP_IPv4HeaderLength byte + IP_IPv4Header []byte + IP_TPHeader []byte + + IP_SrcPort [2]byte + IP_DstPort [2]byte + IP_MappedPort *RP + + IP_NAT_IP [4]byte + IP_NAT_OK bool + + // This IP gets over-written on connect + // IP_VPNSrcIP [4]byte + IP_InterfaceIP [4]byte +) + +func ProcessIngressPacket(packet []byte) bool { + IP_SrcIP[0] = packet[12] + IP_SrcIP[1] = packet[13] + IP_SrcIP[2] = packet[14] + IP_SrcIP[3] = packet[15] + + IP_Protocol = packet[9] + + IP_IPv4HeaderLength = (packet[0] << 4 >> 4) * 32 / 8 + IP_IPv4Header = packet[:IP_IPv4HeaderLength] + IP_TPHeader = packet[IP_IPv4HeaderLength:] + + IP_DstPort[0] = IP_TPHeader[2] + IP_DstPort[1] = IP_TPHeader[3] + + IP_NAT_IP, IP_NAT_OK = AS.AP.REVERSE_NAT_CACHE[IP_SrcIP] + if IP_NAT_OK { + // log.Println("FOUND INGRESS NAT", IP_SrcIP, IP_NAT_IP) + IP_IPv4Header[12] = IP_NAT_IP[0] + IP_IPv4Header[13] = IP_NAT_IP[1] + IP_IPv4Header[14] = IP_NAT_IP[2] + IP_IPv4Header[15] = IP_NAT_IP[3] + + IP_SrcIP[0] = IP_NAT_IP[0] + IP_SrcIP[1] = IP_NAT_IP[1] + IP_SrcIP[2] = IP_NAT_IP[2] + IP_SrcIP[3] = IP_NAT_IP[3] + } + + if IP_Protocol == 6 { + + IP_MappedPort = GetIngressPortMapping(&TCP_o0, IP_SrcIP, IP_DstPort) + if IP_MappedPort == nil { + // log.Println("NO PORT MAPPING", IP_SrcIP, binary.BigEndian.Uint16(IP_DstPort[:])) + return false + } + + } else if IP_Protocol == 17 { + + IP_MappedPort = GetIngressPortMapping(&UDP_o0, IP_SrcIP, IP_DstPort) + if IP_MappedPort == nil { + // log.Println("NO PORT MAPPING", IP_SrcIP, binary.BigEndian.Uint16(IP_DstPort[:])) + return false + } + + } + + IP_TPHeader[2] = IP_MappedPort.Local[0] + IP_TPHeader[3] = IP_MappedPort.Local[1] + + IP_IPv4Header[16] = IP_InterfaceIP[0] + IP_IPv4Header[17] = IP_InterfaceIP[1] + IP_IPv4Header[18] = IP_InterfaceIP[2] + IP_IPv4Header[19] = IP_InterfaceIP[3] + + if EP_Protocol == 17 { + if IP_SrcIP == C.DNS1Bytes && IS_UNIX { + // if IsDNSQuery(EP_TPHeader[8:]) && IS_UNIX { + IP_IPv4Header[12] = PREV_DNS_IP[0] + IP_IPv4Header[13] = PREV_DNS_IP[1] + IP_IPv4Header[14] = PREV_DNS_IP[2] + IP_IPv4Header[15] = PREV_DNS_IP[3] + } + } + + RecalculateAndReplaceIPv4HeaderChecksum(IP_IPv4Header) + RecalculateAndReplaceTransportChecksum(IP_IPv4Header, IP_TPHeader) + + return true +} + +func IsDNSQuery(UDPData []byte) bool { + if len(UDPData) < 12 { + // log.Println("NOT ENOUGH UDP DATA") + return false + } + + // QR == 0 when making a DNS Query + QR := UDPData[2] >> 7 + if QR != 0 { + return false + } + + // AN Count is always 0 for queries + if UDPData[6] != 0 || UDPData[7] != 0 { + // log.Println("AN COUNT OFF", UDPData[6:8]) + return false + } + + // NS Count is always 0 for queries + if UDPData[8] != 0 || UDPData[9] != 0 { + // log.Println("NS COUNT OFF", UDPData[8:10]) + return false + } + + return true +} + +func ProcessEgressDNSQuery(UDPData []byte) (DNSResponse []byte, shouldProcess bool) { + q := new(dns.Msg) + _ = q.Unpack(UDPData) + + x := new(dns.Msg) + x.SetReply(q) + x.Authoritative = true + x.Compress = true + + isCustomDNS := false + for i := range x.Question { + if x.Question[i].Qtype == dns.TypeA { + domain := x.Question[i].Name[0 : len(x.Question[i].Name)-1] + + _, ok := GLOBAL_BLOCK_LIST[domain] + // CreateLog("", "DNS Q: ", domain, len(GLOBAL_BLOCK_LIST), ok) + if ok { + + if GLOBAL_STATE.C.LogBlockedDomains { + CreateLog("", "Domain blocked:", domain) + } + isCustomDNS = true + x.Answer = append(x.Answer, &dns.A{ + Hdr: dns.RR_Header{ + Class: dns.TypeA, + Rrtype: dns.ClassINET, + Name: x.Question[i].Name, + Ttl: 5, + }, + A: net.ParseIP("127.0.0.1"), + }) + + } else { + + IPS, CNAME := DNSAMapping(domain) + if CNAME != "" { + + isCustomDNS = true + x.Answer = append(x.Answer, &dns.CNAME{ + Hdr: dns.RR_Header{ + Class: dns.ClassNONE, + Rrtype: dns.TypeCNAME, + Name: x.Question[i].Name, + Ttl: 5, + }, + Target: CNAME + ".", + }) + + } else if IPS != nil { + isCustomDNS = true + + for ii := range IPS { + x.Answer = append(x.Answer, &dns.A{ + Hdr: dns.RR_Header{ + Class: dns.TypeA, + Rrtype: dns.ClassINET, + Name: x.Question[i].Name, + Ttl: 5, + }, + A: IPS[ii].To4(), + }) + } + } + + } + + } else if x.Question[i].Qtype == dns.TypeTXT { + + TXTS := DNSTXTMapping(x.Question[i].Name[0 : len(x.Question[i].Name)-1]) + if TXTS != nil { + isCustomDNS = true + for ii := range TXTS { + x.Answer = append(x.Answer, &dns.TXT{ + Hdr: dns.RR_Header{ + Class: dns.ClassNONE, + Rrtype: dns.TypeTXT, + Name: x.Question[i].Name, + Ttl: 30, + }, + Txt: []string{TXTS[ii]}, + }) + } + } + + } else if x.Question[i].Qtype == dns.TypeCNAME { + + CNAME := DNSCNameMapping(x.Question[i].Name[0 : len(x.Question[i].Name)-1]) + if CNAME != "" { + isCustomDNS = true + x.Answer = append(x.Answer, &dns.CNAME{ + Hdr: dns.RR_Header{ + Class: dns.ClassNONE, + Rrtype: dns.TypeCNAME, + Name: x.Question[i].Name, + Ttl: 30, + }, + Target: CNAME + ".", + }) + } + + } + } + + if isCustomDNS { + + var err error + DNSResponse, err = x.Pack() + if err != nil { + // log.Println("UNABLE TO PICK DNS RESPONSE: ", err) + return + } + + shouldProcess = true + return + } + + return +} + +func ProcessIngressDNSQuery(TPHeader []byte) bool { + return true +} + +func RecalculateAndReplaceIPv4HeaderChecksum(bytes []byte) { + // Clear checksum bytes + bytes[10] = 0 + bytes[11] = 0 + + // Compute checksum + var csum uint32 + for i := 0; i < len(bytes); i += 2 { + csum += uint32(bytes[i]) << 8 + csum += uint32(bytes[i+1]) + } + for { + // Break when sum is less or equals to 0xFFFF + if csum <= 65535 { + break + } + // Add carry to the sum + csum = (csum >> 16) + uint32(uint16(csum)) + } + + // Flip all the bits and replace checksum + binary.BigEndian.PutUint16(bytes[10:12], ^uint16(csum)) + return +} + +func RecalculateAndReplaceTransportChecksum(IPv4Header []byte, TPPacket []byte) { + if IPv4Header[9] == 6 { + TPPacket[16] = 0 + TPPacket[17] = 0 + } else if IPv4Header[9] == 17 { + TPPacket[6] = 0 + TPPacket[7] = 0 + } + + var csum uint32 + csum += (uint32(IPv4Header[12]) + uint32(IPv4Header[14])) << 8 + csum += uint32(IPv4Header[13]) + uint32(IPv4Header[15]) + csum += (uint32(IPv4Header[16]) + uint32(IPv4Header[18])) << 8 + csum += uint32(IPv4Header[17]) + uint32(IPv4Header[19]) + csum += uint32(uint8(IPv4Header[9])) + tcpLength := uint32(len(TPPacket)) + + csum += tcpLength & 0xffff + csum += tcpLength >> 16 + + length := len(TPPacket) - 1 + for i := 0; i < length; i += 2 { + // For our test packet, doing this manually is about 25% faster + // (740 ns vs. 1000ns) than doing it by calling binary.BigEndian.Uint16. + csum += uint32(TPPacket[i]) << 8 + csum += uint32(TPPacket[i+1]) + } + if len(TPPacket)%2 == 1 { + csum += uint32(TPPacket[length]) << 8 + } + for csum > 0xffff { + csum = (csum >> 16) + (csum & 0xffff) + } + + if IPv4Header[9] == 6 { + binary.BigEndian.PutUint16(TPPacket[16:18], ^uint16(csum)) + } else if IPv4Header[9] == 17 { + binary.BigEndian.PutUint16(TPPacket[6:8], ^uint16(csum)) + } + + return +} diff --git a/core/structs_globals.go b/core/structs_globals.go index be942b9..5ce4a7e 100644 --- a/core/structs_globals.go +++ b/core/structs_globals.go @@ -18,38 +18,50 @@ var PRODUCTION = false var ENABLE_INSTERFACE = false -var A = new(Adapter) -var AS = new(AdapterSettings) -var C = new(Config) -var GLOBAL_STATE = new(State) +var ( + A = new(Adapter) + AS = new(AdapterSettings) + C = new(Config) + GLOBAL_STATE = new(State) +) var letterRunes = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567") // var LastRouterPing = time.Now() var LastConnectionAttemp = time.Now() -var BUFFER_ERROR bool -var IGNORE_NEXT_BUFFER_ERROR bool +var ( + BUFFER_ERROR bool + IGNORE_NEXT_BUFFER_ERROR bool +) var STATE_LOCK = sync.Mutex{} -var TUNNEL_ADAPTER_NAME = "NicelandVPN" -var TUNNEL_ADAPTER_ADDRESS = "10.4.3.2" -var TUNNEL_ADAPTER_ADDRESS_IP = net.IP{10, 4, 3, 2} +var ( + TUNNEL_ADAPTER_NAME = "NicelandVPN" + TUNNEL_ADAPTER_ADDRESS = "10.4.3.2" + TUNNEL_ADAPTER_ADDRESS_IP = net.IP{10, 4, 3, 2} +) var MAC_CONNECTION_SETTINGS *CONNECTION_SETTINGS -var CURRENT_UBBS int = 0 -var CURRENT_DBBS int = 0 -var EGRESS_PACKETS uint64 = 0 -var INGRESS_PACKETS uint64 = 0 +var ( + CURRENT_UBBS int = 0 + CURRENT_DBBS int = 0 + EGRESS_PACKETS uint64 = 0 + INGRESS_PACKETS uint64 = 0 +) // NETWORKING STUFF -var TCP_MAP = make(map[[4]byte]*IP) -var TCP_MAP_LOCK = sync.RWMutex{} +var ( + TCP_MAP = make(map[[4]byte]*IP) + TCP_MAP_LOCK = sync.RWMutex{} +) -var UDP_MAP = make(map[[4]byte]*IP) -var UDP_MAP_LOCK = sync.RWMutex{} +var ( + UDP_MAP = make(map[[4]byte]*IP) + UDP_MAP_LOCK = sync.RWMutex{} +) var DNSWhitelist = make(map[string]bool) @@ -67,14 +79,15 @@ type RemotePort struct { LastActivity time.Time } -var L = new(Logs) -var LogQueue = make(chan LogItem, 10000) -var TAG_ERROR = "ERROR" -var TAG_GENERAL = "GENERAL" -var LogFile *os.File +var ( + L = new(Logs) + LogQueue = make(chan LogItem, 10000) + TAG_ERROR = "ERROR" + TAG_GENERAL = "GENERAL" + LogFile *os.File +) -type LoggerInterface struct { -} +type LoggerInterface struct{} type Logs struct { PING [100]string @@ -177,6 +190,7 @@ type CONFIG_FORM struct { PrevSession *CONTROLLER_SESSION_REQUEST `json:"PrevSlot"` DisableIPv6OnConnect bool `json:"DisableIPv6OnConnect"` CloseConnectionsOnConnect bool `json:"CloseConnectionsOnConnect"` + CustomDNS bool `json:"CustomDNS"` } type Config struct { @@ -191,13 +205,14 @@ type Config struct { Version string RouterFilePath string - PrevSession *CONTROLLER_SESSION_REQUEST `json:"-"` DomainWhitelist string EnabledBlockLists []string + LogBlockedDomains bool DisableIPv6OnConnect bool CloseConnectionsOnConnect bool + CustomDNS bool - CLI bool `json:"-"` + PrevSession *CONTROLLER_SESSION_REQUEST `json:"-"` } type AdapterSettings struct { @@ -573,3 +588,31 @@ type MIB_TCPTABLE_OWNER_PID struct { dwNumEntries uint32 table [30000]MIB_TCPROW_OWNER_PID } + +// Device token struct need for the login respons from user scruct +type DEVICE_TOKEN struct { + DT string `bson:"DT"` + N string `bson:"N"` + Created time.Time `bson:"C"` +} + +// use struct you get from the login request +type User struct { + ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"` + APIKey string `bson:"AK" json:"APIKey"` + Email string `bson:"E"` + TwoFactorEnabled bool `json:"TwoFactorEnabled" bson:"TFE"` + Disabled bool `bson:"D" json:"Disabled"` + Tokens []*DEVICE_TOKEN `json:"Tokens" bson:"T"` + DeviceToken *DEVICE_TOKEN `json:",omitempty" bson:"-"` + + CashCode int `bson:"CSC" json:"CashCode"` + Affiliate string `bson:"AF"` + SubLevel int `bson:"SUL"` + SubExpiration time.Time `bson:"SE"` + TrialStarted time.Time `bson:"TrialStarted" json:"TrialStarted"` + + CancelSub bool `json:"CancelSub" bson:"CS"` + + Version string `json:"Version" bson:"-"` +} diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 09442c8..14cd762 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -6,7 +6,6 @@ import toast, { Toaster } from 'react-hot-toast'; import dayjs from "dayjs"; import "./assets/style/app.scss"; - import { CloseApp, IsProduction } from '../wailsjs/go/main/App'; import { Disconnect, LoadRoutersUnAuthenticated, GetRoutersAndAccessPoints, GetState } from '../wailsjs/go/main/Service'; @@ -27,14 +26,6 @@ import StatsSideBar from "./App/StatsSideBar"; const root = createRoot(document.getElementById('app')); -// window.addEventListener('focus', -// STORE.Cache.Set("focus", true) -// ); - -// window.addEventListener('blur', -// STORE.Cache.Set("focus", false) -// ); - const ToggleError = (e) => { let lastFetch = STORE.Cache.Get("error-timeout") let now = dayjs().unix() @@ -104,8 +95,8 @@ const LaunchApp = () => { try { - console.dir(state.ActiveRouter) - console.log("getting access points") + // console.dir(state.ActiveRouter) + // console.log("getting access points") if (STORE.ActiveRouterSet(state)) { let user = STORE.GetUser() if (user) { @@ -152,9 +143,8 @@ const LaunchApp = () => { try { - console.log("GET STATE!!!!") GetState().then((x) => { - console.dir(x) + // console.debug(x) if (x.Err) { ToggleError(x.Err) setState(newState) @@ -330,6 +320,7 @@ class ErrorBoundary extends React.Component { console.info = function() { } console.warn = function() { } console.error = function() { } + console.debug = function() { } window.console = console } diff --git a/frontend/src/App/Dashboard.jsx b/frontend/src/App/Dashboard.jsx index e402b7e..72a2f11 100644 --- a/frontend/src/App/Dashboard.jsx +++ b/frontend/src/App/Dashboard.jsx @@ -327,19 +327,18 @@ const Dashboard = (props) => { } -