Nmap/Code Standards

From SecWiki
Jump to: navigation, search

Nmap is a large codebase. To keep things manageable, please follow these standards.

Style guidance

Uniform coding style makes hunting bugs easier, and it makes causing bugs harder.

All languages

  • Whitespace is limited to the space (" ", ASCII 0x20) and newline ("\n", ASCII 0x0a). This means:
    • Unix-style line endings ("\n", not "\r\n" or anything else)
    • No tabs. Ever.
  • No trailing whitespace
  • Readable code
    • Expressive, but not over-long variable names
    • Effective use of whitespace (around operators, after commas, etc.)
    • See Python style guidance for more ideas
  • Keep lines under 80 columns
  • UTF-8 encoded source
  • Single newline at EOF - this does NOT mean an empty line, just that the final byte in the file should be 0x0A.

C/C++

  • Indent with 2 spaces.
  • Prefer all lowercase function and variable names, separate terms with underscores. C++ classes should be CamelCase.
  • All macro names must be uppercase, no exception.
  • No space before parenthesis in function calls
  • Opening braces are at the end of the line both for functions and blocks.
  • switch/case have one level of indentation for the cases, and another one for the corresponding blocks
  • Wrap at 80 columns, unless it gets ugly

Lua

  • Indent with 2 spaces.
  • All variables and functions declared local. (Exception for names exported from NSE libraries)
  • NSEdoc when appropriate.
  • No semicolons.
  • Always use explicit endianness in format strings for string.pack and string.unpack
  • Scripts should support Nmap structured output.
  • Do not use the deprecated bin or bit libraries. Use Lua 5.3 string packing and bitwise operators instead.

NSEdoc best-practices

  • All exported (non-local) functions and data structures in a library need NSEdoc.
    • You can use NSEdoc on "private" functions, too, but introduce it with --; instead of --- to indicate private documentation.
  • The first paragraph of a NSEdoc block should be a 1-line summary only.
  • Document tables (as arguments or return values) in a separate @class table block, using @name and @see to associate them.
  • @see doesn't work inline. It needs to be on a line by itself.
    • @see can be used in scripts to link to related scripts, but you must append .nse to the name of the script.
  • For object methods (e.g. Comm.receive), use @name Class.methodname, otherwise only methodname is used.

Python

Follow PEP 8.

Shell

Use POSIX shell language, not Bash. Not picky on which version (SUSv4, POSIX.1, whatever).

  • Scripts should use #!/bin/sh shebang line.

Tools to help

Sample .vimrc

function SetNmapPrefs ()
    "Get the full dirname of the edited file and
    "Check whether we are in an Nmap source tree
    if expand('%:p:h') =~ "/nmap"
        "Set this to the location of nmap-private-dev, if you want
        let nmap_private_dev = "/home/miller/nmap/nmap-m/nmap-private-dev"
        "proper indentation
        set nocindent
        set autoindent
        set smartindent
        set copyindent
        let ext = expand('%:e')
        " *.nse and *.luadoc are Lua
        if ext == "nse" || ext == "luadoc"
            set ft=lua
        endif
        "PEP 8 specifies 4 spaces for indentation
        if &filetype == "python"
            set tabstop=4
            set softtabstop=4
            set shiftwidth=4
        else
            "Indent is 2 spaces, no tabs
            set tabstop=2
            set softtabstop=2
            set shiftwidth=2
        endif
        set expandtab
        set smarttab
        "Complain about trailing whitespace and tab indentation
        let b:ws = matchadd("SpellBad", '\s\+$')
        "Tabs are fine to indent in Makefiles
        if &filetype != "make"
            let b:tabs = matchadd("SpellBad", '^\s*\t\+')
        endif
        "Source the service-probes syntax highlighting
        if nmap_private_dev != "" && expand('%:t') == "nmap-service-probes"
            execute("source " . nmap_private_dev . "fp/sv-highlight.vim")
        endif
    endif
endfunction

au BufRead,BufNewFile * call SetNmapPrefs()

Converting existing code

  • Keep formatting commits separate from code-changing commits
  • Strive for whitespace-only commits for changing indentation (diff -w or diff -b show no changes)
  • If using lua-format, do a whitespace-only indentation commit first, to keep the lua-format changes visible.