понедельник, 19 декабря 2016 г.

Automatically respawning socat.

When user disconnects from socat the process terminates, so you have to restart it.
To automate this process, you can use /etc/inittab.


s1:2345:respawn:/usr/bin/socat tcp-l:12001,reuseaddr,forever /dev/ttyS2,b9600,cs8,cstopb=0,raw,unlink-close=0,echo=0
view raw inittab hosted with ❤ by GitHub
Here
2345 -- is enumeration of runlevels for which process is started,
s1 -- is a unique sequence of 1-4 characters which identifies an entry in inittab.

This socat configuration is used to provide access to serial port (UART / RS-485) over TCP/IP.

воскресенье, 20 ноября 2016 г.

Using Makefile with MSVC on example of libsqlite3_unicode

Cygwin Makefile can be used for building C programs with Visual Studio C compiler in simple regular way without .sln files.

Here I have an examaple on GitHub: https://github.com/Zensey/sqlite3_unicode
It is an minimized extension w/o external dependencies, which adds support of Unicode to sqlite3 used for search and sort operations with non-latin strings.

To build this extension under Windows platform simply run make in Cygwin terminal or run mk.cmd. Below you can see how this Makefile is arranged. Note, that variable M is used to set target architecture of executable object.
CC = cl
LIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
M = /MACHINE:X86
#M = /MACHINE:X64
CFLAGS = /MD /GS /GL /W3 /Gy /Zc:wchar_t /I"..\sqlite-autoconf-3130000" /Gm- /O2 /sdl /fp:precise /D "_WINDLL" /D "_MBCS" /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /EHsc /nologo /c
LINK = /ERRORREPORT:PROMPT /NOLOGO /NXCOMPAT /DYNAMICBASE /OPT:REF /OPT:ICF /IMPLIB:"ext.lib" /DLL /TLBID:1 /LTCG
RM = rm -f
default: all
all: Hello
Hello: sqlite3_unicode.c
$(CC) $(CFLAGS) $(M) sqlite3_unicode.c
link.exe $(LINK) $(M) sqlite3_unicode.obj /OUT:"unicode.dll"
clean veryclean:
$(RM) Hello
view raw Makefile hosted with ❤ by GitHub


вторник, 8 ноября 2016 г.

Setup Syncthing as a service on Windows

To setup and start Syncthing as a service:
- download Syncthing, unpack
- download nssm.exe and put it into directory of syncthing
- put syncthing-svc-setup-win32.bat script into directory of syncthing
- run syncthing-svc-setup-win32.bat as Administrator
set appdir=%~dp0
cd %appdir%
@echo off
@setlocal
nssm.exe install Syncthing syncthing.exe -no-console -no-browser -home="c:\users\litvinov.a\AppData\Local\Syncthing"
nssm set Syncthing AppDirectory %appdir%
nssm.exe edit Syncthing
net start Syncthing
pause

понедельник, 3 октября 2016 г.

How to enumerate serial ports using Setup API (win32)

For me using setupapi is the most strait-forward method to retrieve a list of serial ports on Windows.
I should note, that this code works well on XP and higher.

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <Setupapi.h>
#include <devguid.h>
#include "conio.h"
#include "tchar.h"
// Get-WMIObject Win32_pnpentity | ? Description -like "*CH*"
// Get-WMIObject Win32_pnpentity | ? Manufacturer -like "*chip*"
/* http://stackoverflow.com/a/3439805 */
#include <cfgmgr32.h> // for MAX_DEVICE_ID_LEN, CM_Get_Parent and CM_Get_Device_ID
#define INITGUID
//#include "c:\WinDDK\7600.16385.1\inc\api\devpkey.h"
// include DEVPKEY_Device_BusReportedDeviceDesc from WinDDK\7600.16385.1\inc\api\devpropdef.h
#ifdef DEFINE_DEVPROPKEY
#undef DEFINE_DEVPROPKEY
#endif
#ifdef INITGUID
#define DEFINE_DEVPROPKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const DEVPROPKEY DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid }
#else
#define DEFINE_DEVPROPKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const DEVPROPKEY name
#endif // INITGUID
// include DEVPKEY_Device_BusReportedDeviceDesc from WinDDK\7600.16385.1\inc\api\devpkey.h
DEFINE_DEVPROPKEY(DEVPKEY_Device_BusReportedDeviceDesc, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4); // DEVPROP_TYPE_STRING
DEFINE_DEVPROPKEY(DEVPKEY_Device_ContainerId, 0x8c7ed206, 0x3f8a, 0x4827, 0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c, 2); // DEVPROP_TYPE_GUID
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); // DEVPROP_TYPE_STRING
DEFINE_DEVPROPKEY(DEVPKEY_DeviceDisplay_Category, 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 0x5a); // DEVPROP_TYPE_STRING_LIST
DEFINE_DEVPROPKEY(DEVPKEY_Device_LocationInfo, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 15); // DEVPROP_TYPE_STRING
DEFINE_DEVPROPKEY(DEVPKEY_Device_Manufacturer, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 13); // DEVPROP_TYPE_STRING
DEFINE_DEVPROPKEY(DEVPKEY_Device_SecuritySDS, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
#pragma comment (lib, "setupapi.lib")
typedef BOOL(WINAPI *FN_SetupDiGetDevicePropertyW)(
__in HDEVINFO DeviceInfoSet,
__in PSP_DEVINFO_DATA DeviceInfoData,
__in const DEVPROPKEY *PropertyKey,
__out DEVPROPTYPE *PropertyType,
__out_opt PBYTE PropertyBuffer,
__in DWORD PropertyBufferSize,
__out_opt PDWORD RequiredSize,
__in DWORD Flags
);
wchar_t *subString(wchar_t *someString, int n)
{
wchar_t *new_ = (wchar_t*) malloc(sizeof(wchar_t)*n + 1);
_tcsncpy_s(new_, 5, someString, n);
new_[n] = '\0';
return new_;
}
int main(int argc, char ** argv)
{
static const GUID g1 = { 0x2C7089AA, 0x2E0E, 0x11D1, { 0xB1, 0x14, 0x00, 0xC0, 0x4F, 0xC2, 0xAA, 0xE4 } };
static const GUID g2 = { 0x86E0D1E0, 0x8089, 0x11D0, { 0x9C, 0xE4, 0x08, 0x00, 0x3E, 0x30, 0x1F, 0x73 } };
static const GUID g3 = { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } };
static const GUID g4 = { 0xCC0EF009, 0xB820, 0x42F4, { 0x95, 0xA9, 0x9B, 0xFA, 0x6A, 0x5A, 0xB7, 0xAB } };
static const GUID g5 = { 0x9341CD95, 0x4371, 0x4A37, { 0xA5, 0xAF, 0xFD, 0xB0, 0xA9, 0xD1, 0x96, 0x31 } };
GUID *guidDev = (GUID*)& GUID_DEVCLASS_PORTS;
HDEVINFO hDevInfo = SetupDiGetClassDevs(guidDev, NULL, NULL, DIGCF_PRESENT | DIGCF_PROFILE); /* DIGCF_DEVICEINTERFACE */
int memberIndex = 0;
DWORD dwSize, dwPropertyRegDataType;
WCHAR szBuffer[400];
DEVPROPTYPE ulPropertyType;
TCHAR *id = NULL;
TCHAR *vid = NULL;
TCHAR *pid = NULL;
TCHAR *name = NULL;
TCHAR *manuf = NULL;
TCHAR *description = NULL;
SP_DEVINFO_DATA deviceInfoData;
FN_SetupDiGetDevicePropertyW fn_SetupDiGetDevicePropertyW = (FN_SetupDiGetDevicePropertyW) GetProcAddress(GetModuleHandle(TEXT("Setupapi.dll")), "SetupDiGetDevicePropertyW");
while (true) {
id = NULL;
vid = NULL;
pid = NULL;
name = NULL;
manuf = NULL;
description = NULL;
ZeroMemory(&deviceInfoData, sizeof(SP_DEVINFO_DATA));
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (SetupDiEnumDeviceInfo(hDevInfo, memberIndex, &deviceInfoData) == FALSE) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
break;
}
}
dwSize = sizeof(szBuffer);
SetupDiGetDeviceInstanceId(hDevInfo, &deviceInfoData, szBuffer, dwSize, &dwSize);
szBuffer[dwSize] = '\0';
id = _wcsdup(szBuffer);
vid = wcsstr(szBuffer, _T("VID_"));
if (vid) {
vid += 4;
vid = subString(vid, 4);
}
pid = wcsstr(szBuffer, _T("PID_"));
if (pid) {
pid += 4;
pid = subString(pid, 4);
}
if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &deviceInfoData, SPDRP_DEVICEDESC, &dwPropertyRegDataType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize)) {
description = _wcsdup(szBuffer);
}
if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &deviceInfoData, SPDRP_MFG, &dwPropertyRegDataType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize)) {
manuf = _wcsdup(szBuffer);
}
TCHAR szHardwareIDs[4096];
if (SetupDiGetDeviceRegistryProperty(hDevInfo, &deviceInfoData, SPDRP_HARDWAREID,
&dwPropertyRegDataType, (BYTE*)szHardwareIDs,
sizeof(szHardwareIDs), // The size, in bytes
&dwSize)) {
LPCTSTR pszId;
_tprintf(TEXT("Hardware IDs:\n"));
for (pszId = szHardwareIDs;
*pszId != TEXT('\0') && pszId + dwSize / sizeof(TCHAR) <= szHardwareIDs + ARRAYSIZE(szHardwareIDs);
pszId += lstrlen(pszId) + 1) {
_tprintf(TEXT(" -> \"%s\"\n"), pszId);
}
}
HKEY hkey = SetupDiOpenDevRegKey(hDevInfo, &deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if (hkey != INVALID_HANDLE_VALUE) {
dwSize = sizeof(szBuffer);
if (RegQueryValueEx(hkey, _T("PortName"), NULL, NULL, (LPBYTE)&szBuffer, &dwSize) == ERROR_SUCCESS) {
szBuffer[dwSize] = '\0';
name = _wcsdup(szBuffer);
}
}
if (fn_SetupDiGetDevicePropertyW) { // Vista and higher
if (fn_SetupDiGetDevicePropertyW(hDevInfo, &deviceInfoData, &DEVPKEY_Device_Manufacturer,
&ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0)) {
manuf = _wcsdup(szBuffer);
}
} else { // XP
}
_tprintf(TEXT("Id: %s \n"), id);
_tprintf(TEXT("Vid: %s \n"), vid);
_tprintf(TEXT("Pid: %s \n"), pid);
_tprintf(TEXT("Device Description: %s\n"), description);
_tprintf(TEXT("Manufacturer: %s \n"), manuf);
_tprintf(_T("PortName %s\n"), name);
free(id);
free(vid);
free(pid);
free(description);
free(manuf);
free(name);
RegCloseKey(hkey);
memberIndex++;
}
if (hDevInfo) {
SetupDiDestroyDeviceInfoList(hDevInfo);
}
_getch();
return 0;
}
view raw EnumPorts.cpp hosted with ❤ by GitHub


Example of output:

Hardware IDs:
-> "USB\VID_10C4&PID_EA60&REV_0100"
-> "USB\VID_10C4&PID_EA60"
Id: USB\VID_10C4&PID_EA60\0001
Vid: 10C4
Pid: EA60
Device Description: Silicon Labs CP210x USB to UART Bridge
Manufacturer: Silicon Laboratories
PortName COM18
Hardware IDs:
-> "MF\PCI9710_COM"
Id: MF\PCI#VEN_9710&DEV_9835&SUBSYS_00121000&REV_01\6&20BEF77D&0&0800E5#CHILD0000
Vid: (null)
Pid: (null)
Device Description: PCI Serial Port
Manufacturer: MosChip Semiconductor Technology Ltd
PortName COM6
I'm going to offer this code to guys of node-serialport, because current method doesn't work well on some setups with antivir.


Update: The patch is ready https://github.com/Zensey/node-serialport/commit/b4c8e830d248c4f7e3be0fd0d2cd56a18159f2d9


References:
1. https://social.msdn.microsoft.com/Forums/vstudio/en-US/2555943e-0c69-4357-a85b-d6540bcaaf84/using-setupapi-to-return-all-guiddevclassdisplay?forum=vcgeneral
2. http://stackoverflow.com/a/3439805
3. https://gist.github.com/Zensey/7bd7781a28d6be306be5cdd70539dc65

SSH over TLS/SSL

This method is appliable to situation when you are at restricted network where connection to external ssh is not allowed. In addition to interactive ssh connect to server you can setup persistent reverse tunnel to server in order to login from server to client.

On server:

Install stunnel:

$ sudo apt-get install stunnel4

$ openssl genrsa 1024 > stunnel.key
$ openssl req -new -key stunnel.key -x509 -days 1000 -out stunnel.crt
$ cat stunnel.crt stunnel.key > stunnel.pem

$ sudo mv stunnel.pem /etc/stunnel/


Edit stunnel config file: /etc/stunnel/stunnel.conf
pid = /var/run/stunnel.pid
cert = /etc/stunnel/stunnel.pem
[ssh]
accept = 1.1.1.1:443
connect = 127.0.0.1:22
view raw stunnel.conf hosted with ❤ by GitHub

^where 1.1.1.1 -- is your server external ip.

Also edit /etc/default/stunnel4. Set param Enabled=1
Then start stunnel4 service.

On client:

Install socat:
$ sudo apt-get install socat

Add to file .ssh/config
Host 1.1.1.1
ProxyCommand socat - openssl:1.1.1.1:443,verify=0
view raw tun_ssh_config1 hosted with ❤ by GitHub


Connect to your server:
$ ssh user@1.1.1.1

Reverse tunnel with AutoSSH:

First of all add user without shell:

$ sudo useradd -m -s /bin/false autossh

Now login, make a new key and copy it to the server:

$ sudo su -s /bin/bash autossh
autossh@pc:...$ cd ~
autossh@pc:~$ ssh-keygen
autossh@pc:~$ ssh-copy-id -i .ssh/id_rsa.pub remote@1.1.1.1

Also add this to .ssh/config of user autossh:
Host 1.1.1.1
ProxyCommand socat - openssl:1.1.1.1:443,verify=0
ServerAliveInterval 60
ServerAliveCountMax 3
view raw tun_ssh_config2 hosted with ❤ by GitHub


To start reverse tunnel execute:
autossh -M 0 -N -f -R 5001:localhost:22 remote@1.1.1.1
view raw autossh hosted with ❤ by GitHub
To auto-start reverse tunnel during system start add to /etc/rc.local:
su - autossh -s /bin/sh -c "/usr/bin/autossh -M 0 -N -f -R 5001:localhost:22 remote@1.1.1.1"
view raw rc.local hosted with ❤ by GitHub

Now you can test your reverse tunnel from server:
$ ssh -p 5001 user@localhost


пятница, 5 августа 2016 г.

GOST 28147-89 cypher in JavaScript

I'd like to indroduce you my implementation of GOST 28147-89 cypher also known as Magma in JavaScript.

This cypher is used in "Carrdex IMS", an Access Contol System produced by Carddex LLC, to verify and protect identification data of MIFARE proximity cards.

My implementation is pretty small in size, but has support of Cipher Feedback Mode. Its overall 100 lines of source code and has no dependencies.

Below follows an example of how you can use it.


var GOST_28147 = require('./index')
const _MeshingKeys_8i32 = [
0x97c8c203, 0x6d99ee04, 0x9e7136db, 0x4a07c0c3,
0x31a11d29, 0xeccd7d4e, 0xc0fd6a8f, 0x02be4a45
];
const _SubstitutionBoxes = [
[ 4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3 ],
[ 14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9 ],
[ 5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11 ],
[ 7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3 ],
[ 6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2 ],
[ 4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14 ],
[ 13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12 ],
[ 1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12 ]
]
var gamma = new Buffer([
0x40, 0xE0, 0x3C, 0x7E,
0xB3, 0x29, 0x86, 0x6C,
])
var msg = new Buffer([
0x01, 0x02, 0x03, 0x04,
0x01, 0x02, 0x03, 0x04,
])
var eng = new GOST_28147(_MeshingKeys_8i32, _SubstitutionBoxes);
eng.setGamma(gamma.readUInt32LE(0), gamma.readUInt32LE(4))
eng.execute_gammingMode(8/4, msg, true);
console.log('cypher:', msg)
eng.setGamma(gamma.readUInt32LE(0), gamma.readUInt32LE(4))
eng.execute_gammingMode(8/4, msg, true);
console.log('original:', msg)
view raw gost_ex1.js hosted with ❤ by GitHub