Skip to content

Commit

Permalink
Initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
brthanmathwoag committed May 12, 2017
1 parent 106fec2 commit 0f518ce
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
bin/*
19 changes: 19 additions & 0 deletions Makefile
@@ -0,0 +1,19 @@
BIN = bin

$(BIN)/inet.so: \
$(BIN) \
inet.c \

gcc -Wall -g -fPIC -shared inet.c -o $(BIN)/inet.so


$(BIN):
mkdir $(BIN)

clean:
rm -rf $(BIN)/*

test: \
$(BIN)/inet.so

./testsuite.sh
32 changes: 31 additions & 1 deletion README.md
@@ -1,2 +1,32 @@
# sqlite-inet
Converting IP addresses between string and numeric representation

This Sqlite extension provides `inet_aton()` and `inet_ntoa()` functions
for converting IP adresses between their string and numeric representation.

## Usage

```
$ make
$ sqlite3
sqlite> .load bin/inet.so
sqlite> select inet_ntoa(3232235777);
192.168.1.1
```

If you don't want to compile code yourself you can download binaries from here:

| Operating System | SHA256 |
| ------------------------------------------------------------------- | ------ |
| [Linux 64-bit](https://tznvy.eu/download/sqlite-inet/amd64/inet.so) | `4147cf5226184a5761cbe87d6a06bdf22289db57819069667cf46362c4e58fad` |
| [Linux 32-bit](https://tznvy.eu/download/sqlite-inet/i386/inet.so) | `5912909bb63640c80b08b83e53e36c672c6474be98d56922525bae57923b718f` |

## Misc

The functions behave like their [MariaDB analogs](https://mariadb.com/kb/en/mariadb/inet_ntoa/), that is,
they expect integers in host byte order,
rather than network byte order as expected by [C functions](https://linux.die.net/man/3/inet_ntoa).
For more info, see [this bug report](https://bugs.mysql.com/bug.php?id=34030#c197546).

When invoked with NULL, NULL is returned.

When invoked with otherwise incorrect data, an error is raised.
108 changes: 108 additions & 0 deletions inet.c
@@ -0,0 +1,108 @@
/*
** 2017-05-12
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This SQLite extension implements inet_aton() and inet_ntoa() functions.
*/
#include <sqlite3ext.h>
SQLITE_EXTENSION_INIT1
#include <arpa/inet.h>
#include <assert.h>
#include <string.h>

static void inet_aton_impl(
sqlite3_context *context,
int argc,
sqlite3_value **argv)
{
const char *zIn;
struct in_addr sInAddr;

assert(argc == 1);
if (sqlite3_value_type(argv[0]) == SQLITE_NULL)
{
return;
}

zIn = (const char*)sqlite3_value_text(argv[0]);

if (inet_aton(zIn, &sInAddr) == 0)
{
sqlite3_result_error(context, "Passed a malformed IP address", -1);
return;
}

sqlite3_result_int(context, ntohl(sInAddr.s_addr));
}

static void inet_ntoa_impl(
sqlite3_context *context,
int argc,
sqlite3_value **argv)
{
struct in_addr sInAddr;
int nIn;
char* zOut;
int nOut = 0;

assert(argc == 1);
if (sqlite3_value_type(argv[0]) == SQLITE_NULL)
{
return;
}

nIn = sqlite3_value_int(argv[0]);
sInAddr.s_addr = htonl(nIn);
zOut = inet_ntoa(sInAddr);
nOut = strlen(zOut);
sqlite3_result_text(context, (char*)zOut, nOut, SQLITE_TRANSIENT);
}

#ifdef _WIN32
__declspec(dllexport)
#endif

int sqlite3_inet_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi)
{
int rc = SQLITE_OK;

SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */

rc = sqlite3_create_function(
db,
"inet_aton",
1,
SQLITE_UTF8,
0,
inet_aton_impl,
0,
0);

if (rc != SQLITE_OK) {
return rc;
}

rc = sqlite3_create_function(
db,
"inet_ntoa",
1,
SQLITE_UTF8,
0,
inet_ntoa_impl,
0,
0);

return rc;
}
76 changes: 76 additions & 0 deletions testsuite.sh
@@ -0,0 +1,76 @@
#!/bin/bash

ANY_FAILED=0

main() {
ANY_FAILED="0"

testcase "inet_ntoa and inet_aton are inverse" \
"select inet_ntoa(inet_aton('33.44.55.66'));" \
"33.44.55.66"

if [ "$?" != "0" ]; then ANY_FAILED="1"; fi

testcase "inet_aton converts valid string address to number" \
"select inet_aton('12.34.56.78');" \
"203569230"

if [ "$?" != "0" ]; then ANY_FAILED="1"; fi

testcase "inet_ntoa converts valid numeric address to string" \
"select inet_ntoa(1924046976);" \
"114.174.160.128"

if [ "$?" != "0" ]; then ANY_FAILED="1"; fi

testcase "inet_ntoa ignores NULLs" \
"select inet_ntoa(NULL);" \
""

if [ "$?" != "0" ]; then ANY_FAILED="1"; fi

testcase "inet_aton ignores NULLs" \
"select inet_aton(NULL);" \
""

if [ "$?" != "0" ]; then ANY_FAILED="1"; fi

testcase "inet_aton fails when fed arbitrary strings" \
"select inet_aton('999.999.999.999');" \
"Error: near line 2: Passed a malformed IP address"

if [ "$?" != "0" ]; then ANY_FAILED="1"; fi

return $ANY_FAILED
}

testcase() {
CASE_NAME="$1"
CODE="$2"
EXPECTED="$3"

FAILED="0"

printf "$CASE_NAME\t-\t"

OUTPUT=$(
sqlite3 2>&1 << EOF
.load bin/inet
$CODE
EOF
)

RC="$?"

if [ "$EXPECTED" != "$OUTPUT" ]; then
printf "FAILED\n"
printf "\tAssertion failed. Expected: '$EXPECTED', Actual: '$OUTPUT'\n"
FAILED="1"
else
printf "OK\n"
fi

return $FAILED
}

main

0 comments on commit 0f518ce

Please sign in to comment.