14 Commits

Author SHA1 Message Date
0330d2d17f Bump version 2022-01-26 10:50:41 +10:30
58a078b9f9 Move protocol version to a const 2022-01-26 10:49:23 +10:30
3baccaccac Improve test 2022-01-26 10:47:29 +10:30
74123021be Add LICENSE 2022-01-26 08:50:12 +10:30
80d23b514c Add file timestamps 2022-01-26 08:49:54 +10:30
1026cc5dd9 More docco fixes 2022-01-25 23:26:52 +10:30
cb34fe2883 Fix typo 2022-01-25 23:25:04 +10:30
b7558e9d01 Fix typo 2022-01-25 23:23:40 +10:30
767d8be277 Add copy and paste instructions for downloading 2022-01-25 23:22:52 +10:30
239a6d6804 Even more documentation improvements 2022-01-25 23:16:54 +10:30
1491ad9351 Add acknowledgement of awesomeness 2022-01-25 23:00:09 +10:30
96de06e4e0 Improve docs 2022-01-25 22:59:25 +10:30
8f9eb05ddb Update docs 2022-01-25 22:54:11 +10:30
c471f9f4cc Update README 2022-01-25 22:50:23 +10:30
7 changed files with 235 additions and 21 deletions

21
LICENSE.txt Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Justin Hawkins
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

141
README.md
View File

@@ -1,3 +1,142 @@
# netgiv
TBD
## What is this?
`netgiv` is a single binary client and server to facilitate sending files across
your local network quickly and easily.
It uses a familiar unix pipeline paradigm, so files can be moved between machines
as part of a pipeline, obviating the need for dealing with temporary files.
`netgiv` automatically detects "copy" (stdin is a pipe) or "paste" (stdout is a
pipe) modes, allowing intuitive use like:
hostA$ pg_dumpall | netgiv
hostB$ netgiv | psql restoredb
Note that since netgiv uses a persistent server, there is no need to setup both ends
of the pipeline in advance (compared to netcat or similar tools).
All data is encrypted in flight (though not in the temporary files on the server)
Access to the server is granted by an authentication token (preshared key) of your
choice.
## Install
### Binary release
Grab the appropriate version from https://github.com/tardisx/netgiv/releases, unzip
and place the binary somewhere on your $PATH.
Copy and paste for the trusting & lazy:
curl -L https://github.com/tardisx/netgiv/releases/download/v0.0.3/netgiv-linux-v0.0.3.zip | funzip > netgiv && chmod a+x netgiv
### Compiling from source
go install github.com/tardisx/netgiv@latest
`netgiv` should end up on your go binary path.
### Compiling from source
Clone this repository, run `go build`.
## Configuration
Configuration of `netgiv` is via a YAML configuration file in
`$HOME/.netgiv/config.yaml`.
Run `netgiv --help-config` to see a sample config file.
The server requires the 'authtoken' and 'port' configuration keys to be set.
The client requires the 'authtoken', 'port' and 'address' configuration keys to be
set.
* `authtoken` - this is any arbitrary string, you should choose something not easy to
guess
* `port` - this is the TCP port the server will listen on (and that the client will
connect to)
* `address` - the IP address or hostname of the `netgiv` server
## Running
To run a server, just run:
netgiv --server
`netgiv` will run in the foreground and log accesses to it.
On any client, run:
$ echo "Hello" | netgiv
To check for success, try:
$ netgiv | cat
You should see "hello" echoed on your terminal.
To check the list of files on the server:
$ netgiv -l
1: UTF-8 text (6 B)
2: application/x-mach-binary (6.5 MB)
3: video/quicktime (14 MB)
4: image/png (1.5 MB)
Note that netgiv tries to identify each file based on file magic heuristics.
If you would like to fetch (paste) a particular file:
netgiv -p 3 > file.mov
Where '3' comes from the information provided in the `-l` output.
Note that providing no `-p` option is the same as `-p X` where X is the highest
numbered upload (most recent).
### Notes on output
Since netgiv is designed to be used in a pipeline, it does not provide any
output on successful execution (apart from your actual data on stdout of course!)
If you'd like to see debugging information, use the `--debug` flag.
Note that `netgiv` will send error logs to stderr in cases of problems.
### Alternative ways of providing the authtoken
It's possible that you do not trust the hosts you are running the `netgiv` client on,
or otherwise not want to store your authtoken in a file on there. If that is the case
there are a couple of alternate options:
#### ENV var
The environment variable NETGIV_AUTHTOKEN can be used to provide the authtoken. A
common way to leverage this is to send it when you ssh to a remote host via the
`SendEnv` option (see your ssh_config man page).
#### Interactive
If the authtoken has not been set by any of the above methods, it will be prompted
for interactively (it will not be echoed to the screen). Note that this only applies
to the client - the server must have a config file with an authtoken specified.
# Other notes
## Temporary file storage
The `netgiv` server will store files in your normal system temporary dir. They will
be deleted when the server shuts down (SIGTERM). These files are *not* encrypted.
## Window support
Windows support is marginal, at best, mostly because of the lack of POSIX style
pipes. Bug reports and suggestions for workarounds are welcome.
# Acknowledgements
* thanks to tengig for the name

View File

@@ -59,6 +59,7 @@ func (c *Client) Connect() error {
}
// now we expect to get stuff back until we don't
numFiles := 0
for {
listPacket := secure.PacketListData{}
err := dec.Decode(&listPacket)
@@ -68,8 +69,10 @@ func (c *Client) Connect() error {
if err != nil {
panic(err)
}
fmt.Printf("%d: %s (%s)\n", listPacket.Id, listPacket.Kind, humanize.Bytes(uint64(listPacket.FileSize)))
fmt.Printf("%d: %s (%s) - %s\n", listPacket.Id, listPacket.Kind, humanize.Bytes(uint64(listPacket.FileSize)), listPacket.Timestamp)
numFiles++
}
fmt.Printf("total: %d files\n", numFiles)
conn.Close()
log.Debugf("done listing")
@@ -180,7 +183,7 @@ func (c *Client) connectToServer(op secure.OperationTypeEnum, enc *gob.Encoder,
startPacket := secure.PacketStartRequest{
OperationType: op,
ClientName: "",
ProtocolVersion: "1.0",
ProtocolVersion: ProtocolVersion,
AuthToken: c.authToken,
}
err := enc.Encode(startPacket)

View File

@@ -13,7 +13,9 @@ import (
"github.com/spf13/viper"
)
var CurrentVersion = "v0.0.3"
var CurrentVersion = "v0.0.4"
const ProtocolVersion = "1.1"
type PasteValue struct {
PasteRequired bool

View File

@@ -7,6 +7,7 @@ import (
"errors"
"io"
"net"
"time"
log "github.com/sirupsen/logrus"
@@ -226,8 +227,9 @@ type PacketReceiveDataNext struct {
}
type PacketListData struct {
Id uint32
Filename string
FileSize uint32
Kind string
Id uint32
Filename string
FileSize uint32
Timestamp time.Time
Kind string
}

View File

@@ -2,22 +2,13 @@ package secure
import (
"bytes"
"encoding/gob"
"net"
"testing"
"time"
)
func TestPacketBasic(t *testing.T) {
// pSrc := PacketStart{
// OperationType: 0,
// ClientName: "test1",
// ProtocolVersion: "test2",
// AuthToken: "test3",
// }
// pDst := PacketStart{}
// buf := bytes.Buffer{}
func TestBasic(t *testing.T) {
srcConn, dstConn := net.Pipe()
srcSecConn := SecureConnection{
@@ -71,6 +62,61 @@ func TestPacketBasic(t *testing.T) {
t.Errorf("%v not equal to %v", out[:n], b)
}
}
}
func TestPacketBasic(t *testing.T) {
// test encoding/decoding of packets over the encrypted wire
srcConn, dstConn := net.Pipe()
srcSecConn := SecureConnection{
Conn: srcConn,
SharedKey: &[32]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
},
Buffer: &bytes.Buffer{},
}
dstSecConn := SecureConnection{
Conn: dstConn,
SharedKey: &[32]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
},
Buffer: &bytes.Buffer{},
}
enc := gob.NewEncoder(&srcSecConn)
dec := gob.NewDecoder(&dstSecConn)
packet := PacketStartRequest{
OperationType: OperationTypeReceive,
ClientName: "foo",
ProtocolVersion: "1.1",
AuthToken: "abc123",
}
go func() { enc.Encode(packet) }()
recvPacket := PacketStartRequest{}
dec.Decode(&recvPacket)
if recvPacket.OperationType != OperationTypeReceive {
t.Error("bad OperationType")
}
if recvPacket.ClientName != "foo" {
t.Error("bad ClientName")
}
if recvPacket.ClientName != "foo" {
t.Error("bad ClientName")
}
if recvPacket.AuthToken != "abc123" {
t.Error("bad AuthToken")
}
if recvPacket.ProtocolVersion != "1.1" {
t.Error("bad ProtocolVersion")
}
}

View File

@@ -105,10 +105,10 @@ func (s *Server) handleConnection(conn *net.TCPConn) {
return
}
// tell teh client the dealio
// tell the client if the connection is ok.
startResponse := secure.PacketStartResponse{}
if start.ProtocolVersion != "1.0" {
if start.ProtocolVersion != ProtocolVersion {
log.Errorf("bad protocol version")
startResponse.Response = secure.PacketStartResponseEnumWrongProtocol
enc.Encode(startResponse)
@@ -307,6 +307,7 @@ func (s *Server) handleConnection(conn *net.TCPConn) {
p.Kind = ngf.Kind
p.Id = ngf.Id
p.Filename = ngf.Filename
p.Timestamp = ngf.Timestamp
enc.Encode(p)
}
log.Debugf("done sending list, closing connection")