Skip to content

Commit

Permalink
Merge pull request #330 from atc0005/add-lsimap-tool
Browse files Browse the repository at this point in the history
Add lsimap troubleshooting tool
  • Loading branch information
atc0005 authored Nov 20, 2022
2 parents 3633d12 + 8ba3d13 commit d3f13db
Show file tree
Hide file tree
Showing 13 changed files with 334 additions and 38 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
# Ignore binaries at root of repo (often generated here when testing)
/check_imap_mailbox
/list-emails
/lsimap

# Help prevent accidentally including this credentials file in the repo
/accounts.ini
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
SHELL = /bin/bash

# Space-separated list of cmd/BINARY_NAME directories to build
WHAT = check_imap_mailbox list-emails
WHAT = check_imap_mailbox list-emails lsimap

# TODO: This will need to be standardized across all cmd files in order to
# work as intended.
Expand Down
94 changes: 90 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Various tools used to monitor mail services
- [Features](#features)
- [`check_imap_mailbox`](#check_imap_mailbox)
- [`list-emails`](#list-emails)
- [`lsimap`](#lsimap)
- [Requirements](#requirements)
- [Building source code](#building-source-code)
- [Running](#running)
Expand All @@ -32,13 +33,16 @@ Various tools used to monitor mail services
- [Configuration file](#configuration-file)
- [Settings](#settings)
- [Usage](#usage)
- [`lsimap`](#lsimap-1)
- [Command-line arguments](#command-line-arguments-2)
- [Examples](#examples)
- [`check_imap_mailbox`](#check_imap_mailbox-2)
- [As a Nagios plugin](#as-a-nagios-plugin)
- [Login failure](#login-failure)
- [`list-emails`](#list-emails-2)
- [No options](#no-options)
- [Alternate locations for config file, log and report directories](#alternate-locations-for-config-file-log-and-report-directories)
- [`lsimap`](#lsimap-2)
- [License](#license)
- [References](#references)

Expand All @@ -51,10 +55,11 @@ submit improvements for review and potential inclusion into the project.

This repo contains various tools used to monitor mail services.

| Tool Name | Overall Status | Description |
| -------------------- | -------------- | ---------------------------------------------------------- |
| `check_imap_mailbox` | Stable | Nagios plugin used to monitor mailboxes for items |
| `list-emails` | Stable | Small CLI app used to generate listing of mailbox contents |
| Tool Name | Overall Status | Description |
| -------------------- | -------------- | ------------------------------------------------------------------------ |
| `check_imap_mailbox` | Stable | Nagios plugin used to monitor mailboxes for items |
| `list-emails` | Stable | Small CLI app used to generate listing of mailbox contents |
| `lsimap` | Alpha | Small CLI tool to list advertised capabilities for specified IMAP server |

## Features

Expand Down Expand Up @@ -102,6 +107,21 @@ This repo contains various tools used to monitor mail services.
- the intent is to help prevent MySQL errors when posting summary reports
- e.g., `ERROR 1366 (22007): Incorrect string value`

### `lsimap`

- Quick one-off tool to list advertised capabilities for specified IMAP server
- Leveled logging
- `console writer`: human-friendly, colorized output
- choice of `disabled`, `panic`, `fatal`, `error`, `warn`, `info` (the
default), `debug` or `trace`
- enable `debug` level to monitor submitted IMAP commands and received IMAP
server responses
- TLS IMAP4 connectivity
- port defaults to 993/tcp
- network type defaults to either of IPv4 and IPv6, but optionally limited
to IPv4-only or IPv6-only
- user-specified minimum TLS version

## Requirements

The following is a loose guideline. Other combinations of Go and operating
Expand Down Expand Up @@ -288,6 +308,24 @@ You may also place the file wherever you like and refer to it using the
`-config-file` (full-length flag name). See the [Examples](#examples) and
[Command-line arguments](#command-line-arguments) sections for usage details.

### `lsimap`

#### Command-line arguments

- Flags marked as **`required`** must be set via CLI flag.
- Flags *not* marked as required are for settings where a useful default is
already defined.

| Option | Required | Default | Repeat | Possible | Description |
| --------------- | -------- | -------------- | ------ | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `h`, `help` | No | | No | `-h`, `--help` | Generate listing of all valid command-line options and applicable (short) guidance for using them. |
| `server` | Yes | *empty string* | No | *valid FQDN or IP Address* | The fully-qualified domain name of the remote mail server. |
| `port` | No | `993` | No | *valid IMAP TCP port* | TCP port used to connect to the remote mail server. This is usually the same port used for TLS encrypted IMAP connections. |
| `net-type` | No | `auto` | No | `auto`, `tcp4`, `tcp6` | Limits network connections to remote mail servers to one of the specified types. |
| `min-tls` | No | `tls12` | No | `tls10`, `tls11`, `tls12`, `tls13` | Limits version of TLS used for connections to remote mail servers. |
| `logging-level` | No | `info` | No | `disabled`, `panic`, `fatal`, `error`, `warn`, `info`, `debug`, `trace` | Sets log level. |
| `version` | No | `false` | No | `true`, `false` | Whether to display application version and then immediately exit application |

## Examples

### `check_imap_mailbox`
Expand Down Expand Up @@ -351,6 +389,54 @@ Checking account: email2
OK: Successfully generated reports for accounts: [email protected], [email protected]
```

### `lsimap`

Quick listings for outlook.office365.com and imap.gmail.com.

This tool can be useful for determining at a glance what authentication
mechanisms are supported by an IMAP server.

```console
$ ./lsimap --server outlook.office365.com
6:10AM INF cmd\lsimap\main.go:61 > Connection established to server
6:10AM INF cmd\lsimap\main.go:70 > Gathering pre-login capabilities
6:10AM INF cmd\lsimap\main.go:87 > Capability: AUTH=PLAIN
6:10AM INF cmd\lsimap\main.go:87 > Capability: AUTH=XOAUTH2
6:10AM INF cmd\lsimap\main.go:87 > Capability: CHILDREN
6:10AM INF cmd\lsimap\main.go:87 > Capability: ID
6:10AM INF cmd\lsimap\main.go:87 > Capability: IDLE
6:10AM INF cmd\lsimap\main.go:87 > Capability: IMAP4
6:10AM INF cmd\lsimap\main.go:87 > Capability: IMAP4rev1
6:10AM INF cmd\lsimap\main.go:87 > Capability: LITERAL+
6:10AM INF cmd\lsimap\main.go:87 > Capability: MOVE
6:10AM INF cmd\lsimap\main.go:87 > Capability: NAMESPACE
6:10AM INF cmd\lsimap\main.go:87 > Capability: SASL-IR
6:10AM INF cmd\lsimap\main.go:87 > Capability: UIDPLUS
6:10AM INF cmd\lsimap\main.go:87 > Capability: UNSELECT
6:10AM INF cmd\lsimap\main.go:95 > Connection to server closed

$ ./lsimap --server imap.gmail.com
6:10AM INF cmd\lsimap\main.go:61 > Connection established to server
6:10AM INF cmd\lsimap\main.go:70 > Gathering pre-login capabilities
6:10AM INF cmd\lsimap\main.go:87 > Capability: AUTH=OAUTHBEARER
6:10AM INF cmd\lsimap\main.go:87 > Capability: AUTH=PLAIN
6:10AM INF cmd\lsimap\main.go:87 > Capability: AUTH=PLAIN-CLIENTTOKEN
6:10AM INF cmd\lsimap\main.go:87 > Capability: AUTH=XOAUTH
6:10AM INF cmd\lsimap\main.go:87 > Capability: AUTH=XOAUTH2
6:10AM INF cmd\lsimap\main.go:87 > Capability: CHILDREN
6:10AM INF cmd\lsimap\main.go:87 > Capability: ID
6:10AM INF cmd\lsimap\main.go:87 > Capability: IDLE
6:10AM INF cmd\lsimap\main.go:87 > Capability: IMAP4rev1
6:10AM INF cmd\lsimap\main.go:87 > Capability: NAMESPACE
6:10AM INF cmd\lsimap\main.go:87 > Capability: QUOTA
6:10AM INF cmd\lsimap\main.go:87 > Capability: SASL-IR
6:10AM INF cmd\lsimap\main.go:87 > Capability: UNSELECT
6:10AM INF cmd\lsimap\main.go:87 > Capability: X-GM-EXT-1
6:10AM INF cmd\lsimap\main.go:87 > Capability: XLIST
6:10AM INF cmd\lsimap\main.go:87 > Capability: XYZZY
6:10AM INF cmd\lsimap\main.go:95 > Connection to server closed
```

## License

From the [LICENSE](LICENSE) file:
Expand Down
1 change: 1 addition & 0 deletions cmd/check_imap_mailbox/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func main() {

return
}
logger.Debug().Msg("Connection established to server")

if loginErr := mbxs.Login(c, account.Username, account.Password, logger); loginErr != nil {
logger.Error().Err(loginErr).Msg("Login error occurred")
Expand Down
1 change: 1 addition & 0 deletions cmd/list-emails/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ func main() {

return
}
logger.Info().Msg("Connection established to server")

if loginErr := mbxs.Login(c, account.Username, account.Password, logger); loginErr != nil {
logger.Error().Err(loginErr).Msg("failed to login to server")
Expand Down
18 changes: 18 additions & 0 deletions cmd/lsimap/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2022 Adam Chalkley
//
// https://github.com/atc0005/check-mail
//
// Licensed under the MIT License. See LICENSE file in the project root for
// full license information.

// Small CLI tool to list advertised capabilities for specified IMAP server.
//
// See our [GitHub repo]:
//
// - to review documentation (including examples)
// - for the latest code
// - to file an issue or submit improvements for review and potential
// inclusion into the project
//
// [GitHub repo]: https://github.com/atc0005/check-mail
package main
98 changes: 98 additions & 0 deletions cmd/lsimap/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright 2022 Adam Chalkley
//
// https://github.com/atc0005/check-mail
//
// Licensed under the MIT License. See LICENSE file in the project root for
// full license information.

//go:generate go-winres make --product-version=git-tag --file-version=git-tag

package main

import (
"errors"
"fmt"
"os"
"sort"

"github.com/atc0005/check-mail/internal/config"
"github.com/atc0005/check-mail/internal/mbxs"
"github.com/rs/zerolog"
)

func main() {

// Setup configuration by parsing user-provided flags
cfg, cfgErr := config.New(config.AppType{InspectorIMAPCaps: true})
switch {
case errors.Is(cfgErr, config.ErrVersionRequested):
fmt.Println(config.Version())

return

case cfgErr != nil:

// We make some assumptions when setting up our logger as we do not
// have a working configuration based on sysadmin-specified choices.
consoleWriter := zerolog.ConsoleWriter{Out: os.Stderr}
logger := zerolog.New(consoleWriter).With().Timestamp().Caller().Logger()

logger.Err(cfgErr).Msg("Error initializing application")

return
}

logger := cfg.Log.With().Logger()

// We're reusing the common "Accounts" field (and flags) in order to
// obtain specified server and port values vs adding standalone fields and
// flags; this is effectively a loop of 1 iteration (at least for now). At
// some point we may expand the scope of this tool to handle evaluating
// mail servers for a collection of accounts, so using a workflow intended
// for collections is probably appropriate.
for _, account := range cfg.Accounts {

// Open connection to IMAP server
c, err := mbxs.Connect(account.Server, account.Port, cfg.NetworkType, cfg.MinTLSVersion(), logger)
if err != nil {
logger.Error().Err(err).Msg("error connecting to server")
os.Exit(1)
}
logger.Info().Msg("Connection established to server")

// Enable client network command/response logging if global logging
// level indicates user wishes to see verbose details.
if zerolog.GlobalLevel() == zerolog.DebugLevel ||
zerolog.GlobalLevel() == zerolog.TraceLevel {
c.SetDebug(&logger)
}

logger.Info().Msg("Gathering pre-login capabilities")
capabilities, err := c.Capability()
if err != nil {
logger.Error().Err(err).Msg("Unable to list server capabilities")
os.Exit(1)
}

caps := make([]string, 0, len(capabilities))
for k, v := range capabilities {
if v {
caps = append(caps, k)
}
}

sort.Strings(caps)
// logger.Info().Msgf("Capabilities: %v", caps)
for _, capability := range caps {
logger.Info().Msgf("Capability: %v", capability)
}

logger.Debug().Msg("Closing connection to server")
if err := c.Logout(); err != nil {
logger.Error().Err(err).Msg("failed to close connection to server")
os.Exit(1)
}
logger.Info().Msg("Connection to server closed")

}
}
53 changes: 53 additions & 0 deletions cmd/lsimap/winres/winres.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"RT_MANIFEST": {
"#1": {
"0409": {
"identity": {
"name": "",
"version": ""
},
"description": "Small CLI tool to list advertised capabilities for specified IMAP server",
"minimum-os": "win7",
"execution-level": "as invoker",
"ui-access": false,
"auto-elevate": false,
"dpi-awareness": "system",
"disable-theming": false,
"disable-window-filtering": false,
"high-resolution-scrolling-aware": false,
"ultra-high-resolution-scrolling-aware": false,
"long-path-aware": false,
"printer-driver-isolation": false,
"gdi-scaling": false,
"segment-heap": false,
"use-common-controls-v6": false
}
}
},
"RT_VERSION": {
"#1": {
"0000": {
"fixed": {
"file_version": "0.0.0.0",
"product_version": "0.0.0.0"
},
"info": {
"0409": {
"Comments": "Part of the atc0005/check-mail project",
"CompanyName": "github.com/atc0005",
"FileDescription": "Small CLI tool to list advertised capabilities for specified IMAP server",
"FileVersion": "",
"InternalName": "lsimap",
"LegalCopyright": "© Adam Chalkley. Licensed under MIT.",
"LegalTrademarks": "",
"OriginalFilename": "main.go",
"PrivateBuild": "",
"ProductName": "check-mail",
"ProductVersion": "",
"SpecialBuild": ""
}
}
}
}
}
}
9 changes: 9 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ type AppType struct {
//
// Basic Authentication is used to login.
ReporterIMAPMailboxBasicAuth bool

// InspectorIMAPCaps represents an application used for one-off or
// isolated checks of an IMAP server's advertised capabilities.
//
// Unlike a monitoring plugin which is focused on specific attributes
// resulting in a severity-based outcome, an Inspector application is
// intended for examining a small set of targets for
// informational/troubleshooting purposes.
InspectorIMAPCaps bool
}

// MailAccount represents an email account listed within a configuration file.
Expand Down
10 changes: 8 additions & 2 deletions internal/config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,20 @@ func (c *Config) handleFlagsConfig(appType AppType) {
flag.StringVar(&c.NetworkType, "net-type", defaultNetworkType, networkTypeFlagHelp)
flag.StringVar(&c.minTLSVersion, "min-tls", defaultMinTLSVersion, minTLSVersionFlagHelp)

// currently only applies to list-emails app, don't expose to Nagios plugin
// Only applies to Reporter app
if appType.ReporterIMAPMailboxBasicAuth {
flag.StringVar(&c.ConfigFile, "config-file", defaultINIConfigFileName, iniConfigFileFlagHelp)
flag.StringVar(&c.ReportFileOutputDir, "report-file-dir", defaultReportFileOutputDir, reportFileOutputDirFlagHelp)
flag.StringVar(&c.LogFileOutputDir, "log-file-dir", defaultLogFileOutputDir, logFileOutputDirFlagHelp)
}

// currently only applies to Nagios plugin
// Inspector app
if appType.InspectorIMAPCaps {
flag.StringVar(&account.Server, "server", defaultServer, serverFlagHelp)
flag.IntVar(&account.Port, "port", defaultPort, portFlagHelp)
}

// Basic Auth Plugin
if appType.PluginIMAPMailboxBasicAuth {
flag.Var(&account.Folders, "folders", foldersFlagHelp)
flag.StringVar(&account.Username, "username", defaultUsername, usernameFlagHelp)
Expand Down
Loading

0 comments on commit d3f13db

Please sign in to comment.