From 9dc7a9528153ba8d2afbd0e651ed120cb7d2f71c Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Thu, 3 Sep 2026 14:46:42 +0300 Subject: [PATCH] sync SVN r18069 --- docs/conexiuni-tunel-ssh-odbc.md | 374 +++++++++++++++---------------- 1 file changed, 187 insertions(+), 187 deletions(-) diff --git a/docs/conexiuni-tunel-ssh-odbc.md b/docs/conexiuni-tunel-ssh-odbc.md index eec86d7..b8998ee 100644 --- a/docs/conexiuni-tunel-ssh-odbc.md +++ b/docs/conexiuni-tunel-ssh-odbc.md @@ -1,187 +1,187 @@ -# Conexiuni la bazele de productie: tunel SSH (Bitvise) + ODBC/TNS - -Cum se ajunge, de pe statia de lucru, la un Oracle care nu e expus direct in internet. Valabil -pentru toate proiectele ROA. Scopul documentului: sa nu se mai piarda o sesiune intreaga -redescoperind lantul. - -> **Fara credentiale in git.** Acest fisier NU contine parole, si nici un fisier din repo nu -> trebuie sa contina. Parolele stau in profilul Bitvise (criptate cu DPAPI, legate de contul -> Windows) si in capul celui care lucreaza. Daca ai nevoie de o parola pe care nu o ai, cere-o - -> nu o cauta prin fisiere si **nu o ghici**: Oracle poate avea `FAILED_LOGIN_ATTEMPTS` in profil, -> iar cateva incercari gresite blocheaza contul de schema in PRODUCTIE. - -## Lantul, pe scurt - -``` -statie -> [tunel SSH Bitvise] -> 127.0.0.1:1521 -> Oracle de pe serverul de productie - ^ - aliasul TNS din instantclient\tnsnames.ora arata AICI - ^ - DSN-ul ODBC cu acelasi nume e ce primeste goConn.Connect() -``` - -Trei nume trebuie sa se potriveasca, si e usor de ratat: **profilul Bitvise** (ce port local -deschide), **aliasul TNS** (ce host:port foloseste) si **DSN-ul ODBC** (ce alias TNS foloseste). - -## 1. Tunelul SSH - -Profilele Bitvise (`.tlp`) stau in `D:\GoogleDrive\` (ex. `vending.tlp`). Un profil contine -gazda, portul, utilizatorul, parola criptata, cheile de gazda deja acceptate si **regulile de -port forwarding** - de obicei `127.0.0.1:1521 -> localhost:1521`. - -Ridicare din linie de comanda, fara interfata grafica: - -```powershell -$exe = 'C:\Program Files (x86)\Bitvise SSH Client\stnlc.exe' -Start-Process $exe -ArgumentList '-profile=D:\GoogleDrive\vending.tlp' -WindowStyle Hidden ` - -RedirectStandardOutput "$env:TEMP\stnlc_out.txt" -RedirectStandardError "$env:TEMP\stnlc_err.txt" -``` - -`stnlc` foloseste singur parola stocata in profil - **nu o trece pe linia de comanda**, ar ajunge -in istoricul shell-ului. Ruleaza sub acelasi cont Windows sub care a fost salvat profilul,altfel -DPAPI nu poate decripta parola. - -Verificare ca tunelul chiar e sus (nu te baza pe faptul ca procesul traieste): - -```powershell -(Test-NetConnection 127.0.0.1 -Port 1521 -WarningAction SilentlyContinue).TcpTestSucceeded -``` - -In `stnlc_out.txt` linia care conteaza e `Added client-to-server forwarding rule on -127.0.0.1:1521 to localhost:1521.` Inchidere: opreste procesul `stnlc`. - -**Capcana**: un singur port local 1521 pentru mai multe destinatii. Daca ai deja un tunel ridicat -catre alt client, al doilea nu mai poate lega portul si vei interoga **alta baza** fara sa-ti dai -seama. Verifica intotdeauna cu ce te-ai conectat (vezi pasul 4). - -**Capcana inrudita**: interfata grafica `BvSsh.exe` poate tine portul 1521 legat pe `0.0.0.0` cu o -sesiune moarta - `sqlplus` raspunde atunci `ORA-12541: TNS:no listener`, desi "tunelul pare sus". -`stnlc` isi poate lega totusi propria regula pe `127.0.0.1:1521` peste ea si merge. Nu te lua dupa -`netstat`: proba reala e interogarea din pasul 4. - -## 2. Aliasul TNS - -`D:\ROA\instantclient_19_18\tnsnames.ora` (si `instantclient_11_2_0_2` pentru driverul ODBC pe -32 de biti). Aliasurile care merg prin tunel arata spre `127.0.0.1`: - -``` -VENDING = - (DESCRIPTION = - (ADDRESS_LIST = (ADDRESS = (PROTOCOL = tcp)(HOST = 127.0.0.1)(PORT = 1521))) - (CONNECT_DATA = (SERVICE_NAME = XEPDB1)) - ) -``` - -Pentru `sqlplus` trebuie `TNS_ADMIN` setat pe folderul care contine `tnsnames.ora`: - -```powershell -$env:TNS_ADMIN = 'D:\ROA\instantclient_19_18' -``` - -## 3. DSN-ul ODBC - -Aplicatia nu foloseste TNS direct: `oConn.Connect(tcHost, tcUser, tcPassword)` -(`oproceduri_comune.prg`) construieste `dsn=;Uid=...;Pwd=...` - deci **`tcHost` e un nume -de DSN ODBC**, nu un host si nu un alias TNS. DSN-urile sunt pe 32 de biti (VFP e pe 32 de biti), -deci in `HKLM\SOFTWARE\WOW6432Node\ODBC\ODBC.INI`, cu driverul din `instantclient_11_2_0_2`. - -Listare rapida: - -```powershell -Get-ChildItem 'HKLM:\SOFTWARE\WOW6432Node\ODBC\ODBC.INI' | - Select-Object -ExpandProperty PSChildName -``` - -De obicei DSN-ul are acelasi nume cu aliasul TNS (`VENDING`, `CENTRAL`, `ROA_CENTRAL`...). -Administrare vizuala: `C:\Windows\SysWOW64\odbcad32.exe` (**nu** cel din `System32`, acela e pe -64 de biti si nu vede DSN-urile VFP). - -## 4. Interogare si verificare - -```powershell -$env:TNS_ADMIN = 'D:\ROA\instantclient_19_18' -& 'D:\ROA\instantclient_19_18\sqlplus.exe' -S -L '/@VENDING' '@script.sql' -``` - -`-L` = o singura incercare de login (nu reincearca la parola gresita). **Foloseste-l intotdeauna -pe productie.** - -Prima interogare, mereu, ca sa stii unde ai nimerit: - -```sql -select user || ' @ ' || sys_context('USERENV','DB_NAME') from dual; -``` - -Pentru extragere in fisier, `spool` scrie **local**, nu pe server: - -```sql -set pagesize 0 feedback off heading off linesize 100 trimspool on termout off -spool D:\cale\locala\iesire.txt -select ...; -spool off -``` - -**Capcana PowerShell**: intr-un here-string cu ghilimele duble (`@"..."@`) PowerShell expandeaza -`$`. Un regex Oracle care se termina cu `$` (ancora de sfarsit) ajunge stricat in fisierul `.sql` -si interogarea intoarce 0 randuri **fara nicio eroare**. Foloseste here-string cu apostrof -(`@'...'@`) si inlocuieste caile printr-un token. - -**Capcana `termout off`**: ascunde si mesajele de eroare. Daca fisierul spool iese gol, ruleaza -din nou fara `termout off` inainte sa banuiesti datele. - -## Schemele cunoscute (fara parole) - -| Tunel / profil | Alias TNS + DSN | Schema Oracle | -|---|---|---| -| `vending.tlp` | `VENDING` | **`VENDING`** (parola standard ROA) | -| conpress | `ROA_CONPRESS` | `xenoti` | - -Profilele Bitvise sunt in **`D:\roa\BITVISE\`** pe statia curenta (`vending.tlp`, `conpress.tlp`, -`clever.tlp`, `automotive.tlp`, `avis.tlp`, `eduard.tlp`, `ems.tlp`, `romfast.tlp`, `sigma.tlp`, -`vadeco.tlp`) - nu in `D:\GoogleDrive\`. Clientul Oracle prezent e `instantclient_11_2_0_2` -(`TNS_ADMIN` se seteaza pe el). `VENDING` este Oracle 18c XE, serviciu `XEPDB1`. - -Masuratoare read-only rulata pe `VENDING` la 03.09.2026: `ROACONT\docs\cercetare\piata_ai_2026_09\` -(`BACKTEST_VENDING.md` plus scripturile din `sql\bt_*.sql`). - -Restul aliasurilor din `tnsnames.ora` (`ROA_CENTRAL`, `CENTRAL105`, `ROA_TEST`, ...) sunt retea -interna si nu au nevoie de tunel. - -## Reguli pe productie - -1. **Doar `SELECT`.** Fara `INSERT`/`UPDATE`/`DELETE`/DDL, fara `ALTER SESSION` care schimba - comportament persistent. Daca ai nevoie de date de lucru, extrage-le si lucreaza local. -2. **Fara ghicit parole** - vezi avertismentul de la inceput. -3. **Interogari marginite**: `fetch first N rows only`, si evita scanarile complete pe tabele - mari in orele de lucru. -4. **Inchide tunelul** cand ai terminat; nu-l lasa deschis peste noapte. -5. **Datele extrase**: codurile fiscale sunt publice si pot sta in repo (vezi - `utile\Teste\cache_anaf\codes_*_reale.txt`). Denumirile de parteneri, adresele, soldurile - **nu** - nu le comite. - -## De unde vin loturile de coduri fiscale pentru teste - -`COMUN\utile\Teste\cache_anaf\codes_1000_reale.txt` a fost extras din productia `vending`, tabela -`nom_parteneri` (23932 randuri, 6382 coduri romanesti distincte): - -```sql -select cif from ( - select distinct regexp_replace(upper(trim(cod_fiscal)), '[^0-9]', '') as cif - from nom_parteneri - where cod_fiscal is not null - and regexp_like(upper(trim(cod_fiscal)), '^(RO)?[[:space:]]*[0-9]{2,10}$') -) where length(cif) between 2 and 10 -order by ora_hash(cif) -fetch first 1000 rows only; -``` - -`order by ora_hash(cif)` da o dispersie **deterministica** (aceeasi de fiecare data), spre -deosebire de `dbms_random`; ordonarea crescuta dupa cod ar fi inclinat lotul spre firme vechi, -deci spre Bucuresti. Suprapunere cu lotul mai vechi de 200: 8 coduri. - -Folosire in proba end-to-end ANAF: - -```powershell -$env:E2E_CODURI = 'D:\ROA\ROADEF\COMUN\utile\Teste\cache_anaf\codes_1000_reale.txt' -$env:E2E_LIMITA = '1000' -``` +# Conexiuni la bazele de productie: tunel SSH (Bitvise) + ODBC/TNS + +Cum se ajunge, de pe statia de lucru, la un Oracle care nu e expus direct in internet. Valabil +pentru toate proiectele ROA. Scopul documentului: sa nu se mai piarda o sesiune intreaga +redescoperind lantul. + +> **Fara credentiale in git.** Acest fisier NU contine parole, si nici un fisier din repo nu +> trebuie sa contina. Parolele stau in profilul Bitvise (criptate cu DPAPI, legate de contul +> Windows) si in capul celui care lucreaza. Daca ai nevoie de o parola pe care nu o ai, cere-o - +> nu o cauta prin fisiere si **nu o ghici**: Oracle poate avea `FAILED_LOGIN_ATTEMPTS` in profil, +> iar cateva incercari gresite blocheaza contul de schema in PRODUCTIE. + +## Lantul, pe scurt + +``` +statie -> [tunel SSH Bitvise] -> 127.0.0.1:1521 -> Oracle de pe serverul de productie + ^ + aliasul TNS din instantclient\tnsnames.ora arata AICI + ^ + DSN-ul ODBC cu acelasi nume e ce primeste goConn.Connect() +``` + +Trei nume trebuie sa se potriveasca, si e usor de ratat: **profilul Bitvise** (ce port local +deschide), **aliasul TNS** (ce host:port foloseste) si **DSN-ul ODBC** (ce alias TNS foloseste). + +## 1. Tunelul SSH + +Profilele Bitvise (`.tlp`) stau in `D:\GoogleDrive\` (ex. `vending.tlp`). Un profil contine +gazda, portul, utilizatorul, parola criptata, cheile de gazda deja acceptate si **regulile de +port forwarding** - de obicei `127.0.0.1:1521 -> localhost:1521`. + +Ridicare din linie de comanda, fara interfata grafica: + +```powershell +$exe = 'C:\Program Files (x86)\Bitvise SSH Client\stnlc.exe' +Start-Process $exe -ArgumentList '-profile=D:\GoogleDrive\vending.tlp' -WindowStyle Hidden ` + -RedirectStandardOutput "$env:TEMP\stnlc_out.txt" -RedirectStandardError "$env:TEMP\stnlc_err.txt" +``` + +`stnlc` foloseste singur parola stocata in profil - **nu o trece pe linia de comanda**, ar ajunge +in istoricul shell-ului. Ruleaza sub acelasi cont Windows sub care a fost salvat profilul,altfel +DPAPI nu poate decripta parola. + +Verificare ca tunelul chiar e sus (nu te baza pe faptul ca procesul traieste): + +```powershell +(Test-NetConnection 127.0.0.1 -Port 1521 -WarningAction SilentlyContinue).TcpTestSucceeded +``` + +In `stnlc_out.txt` linia care conteaza e `Added client-to-server forwarding rule on +127.0.0.1:1521 to localhost:1521.` Inchidere: opreste procesul `stnlc`. + +**Capcana**: un singur port local 1521 pentru mai multe destinatii. Daca ai deja un tunel ridicat +catre alt client, al doilea nu mai poate lega portul si vei interoga **alta baza** fara sa-ti dai +seama. Verifica intotdeauna cu ce te-ai conectat (vezi pasul 4). + +**Capcana inrudita**: interfata grafica `BvSsh.exe` poate tine portul 1521 legat pe `0.0.0.0` cu o +sesiune moarta - `sqlplus` raspunde atunci `ORA-12541: TNS:no listener`, desi "tunelul pare sus". +`stnlc` isi poate lega totusi propria regula pe `127.0.0.1:1521` peste ea si merge. Nu te lua dupa +`netstat`: proba reala e interogarea din pasul 4. + +## 2. Aliasul TNS + +`D:\ROA\instantclient_19_18\tnsnames.ora` (si `instantclient_11_2_0_2` pentru driverul ODBC pe +32 de biti). Aliasurile care merg prin tunel arata spre `127.0.0.1`: + +``` +VENDING = + (DESCRIPTION = + (ADDRESS_LIST = (ADDRESS = (PROTOCOL = tcp)(HOST = 127.0.0.1)(PORT = 1521))) + (CONNECT_DATA = (SERVICE_NAME = XEPDB1)) + ) +``` + +Pentru `sqlplus` trebuie `TNS_ADMIN` setat pe folderul care contine `tnsnames.ora`: + +```powershell +$env:TNS_ADMIN = 'D:\ROA\instantclient_19_18' +``` + +## 3. DSN-ul ODBC + +Aplicatia nu foloseste TNS direct: `oConn.Connect(tcHost, tcUser, tcPassword)` +(`oproceduri_comune.prg`) construieste `dsn=;Uid=...;Pwd=...` - deci **`tcHost` e un nume +de DSN ODBC**, nu un host si nu un alias TNS. DSN-urile sunt pe 32 de biti (VFP e pe 32 de biti), +deci in `HKLM\SOFTWARE\WOW6432Node\ODBC\ODBC.INI`, cu driverul din `instantclient_11_2_0_2`. + +Listare rapida: + +```powershell +Get-ChildItem 'HKLM:\SOFTWARE\WOW6432Node\ODBC\ODBC.INI' | + Select-Object -ExpandProperty PSChildName +``` + +De obicei DSN-ul are acelasi nume cu aliasul TNS (`VENDING`, `CENTRAL`, `ROA_CENTRAL`...). +Administrare vizuala: `C:\Windows\SysWOW64\odbcad32.exe` (**nu** cel din `System32`, acela e pe +64 de biti si nu vede DSN-urile VFP). + +## 4. Interogare si verificare + +```powershell +$env:TNS_ADMIN = 'D:\ROA\instantclient_19_18' +& 'D:\ROA\instantclient_19_18\sqlplus.exe' -S -L '/@VENDING' '@script.sql' +``` + +`-L` = o singura incercare de login (nu reincearca la parola gresita). **Foloseste-l intotdeauna +pe productie.** + +Prima interogare, mereu, ca sa stii unde ai nimerit: + +```sql +select user || ' @ ' || sys_context('USERENV','DB_NAME') from dual; +``` + +Pentru extragere in fisier, `spool` scrie **local**, nu pe server: + +```sql +set pagesize 0 feedback off heading off linesize 100 trimspool on termout off +spool D:\cale\locala\iesire.txt +select ...; +spool off +``` + +**Capcana PowerShell**: intr-un here-string cu ghilimele duble (`@"..."@`) PowerShell expandeaza +`$`. Un regex Oracle care se termina cu `$` (ancora de sfarsit) ajunge stricat in fisierul `.sql` +si interogarea intoarce 0 randuri **fara nicio eroare**. Foloseste here-string cu apostrof +(`@'...'@`) si inlocuieste caile printr-un token. + +**Capcana `termout off`**: ascunde si mesajele de eroare. Daca fisierul spool iese gol, ruleaza +din nou fara `termout off` inainte sa banuiesti datele. + +## Schemele cunoscute (fara parole) + +| Tunel / profil | Alias TNS + DSN | Schema Oracle | +|---|---|---| +| `vending.tlp` | `VENDING` | **`VENDING`** (parola standard ROA) | +| conpress | `ROA_CONPRESS` | `xenoti` | + +Profilele Bitvise sunt in **`D:\roa\BITVISE\`** pe statia curenta (`vending.tlp`, `conpress.tlp`, +`clever.tlp`, `automotive.tlp`, `avis.tlp`, `eduard.tlp`, `ems.tlp`, `romfast.tlp`, `sigma.tlp`, +`vadeco.tlp`) - nu in `D:\GoogleDrive\`. Clientul Oracle prezent e `instantclient_11_2_0_2` +(`TNS_ADMIN` se seteaza pe el). `VENDING` este Oracle 18c XE, serviciu `XEPDB1`. + +Masuratoare read-only rulata pe `VENDING` la 03.09.2026: `ROACONT\docs\cercetare\piata_ai_2026_09\` +(`BACKTEST_VENDING.md` plus scripturile din `sql\bt_*.sql`). + +Restul aliasurilor din `tnsnames.ora` (`ROA_CENTRAL`, `CENTRAL105`, `ROA_TEST`, ...) sunt retea +interna si nu au nevoie de tunel. + +## Reguli pe productie + +1. **Doar `SELECT`.** Fara `INSERT`/`UPDATE`/`DELETE`/DDL, fara `ALTER SESSION` care schimba + comportament persistent. Daca ai nevoie de date de lucru, extrage-le si lucreaza local. +2. **Fara ghicit parole** - vezi avertismentul de la inceput. +3. **Interogari marginite**: `fetch first N rows only`, si evita scanarile complete pe tabele + mari in orele de lucru. +4. **Inchide tunelul** cand ai terminat; nu-l lasa deschis peste noapte. +5. **Datele extrase**: codurile fiscale sunt publice si pot sta in repo (vezi + `utile\Teste\cache_anaf\codes_*_reale.txt`). Denumirile de parteneri, adresele, soldurile + **nu** - nu le comite. + +## De unde vin loturile de coduri fiscale pentru teste + +`COMUN\utile\Teste\cache_anaf\codes_1000_reale.txt` a fost extras din productia `vending`, tabela +`nom_parteneri` (23932 randuri, 6382 coduri romanesti distincte): + +```sql +select cif from ( + select distinct regexp_replace(upper(trim(cod_fiscal)), '[^0-9]', '') as cif + from nom_parteneri + where cod_fiscal is not null + and regexp_like(upper(trim(cod_fiscal)), '^(RO)?[[:space:]]*[0-9]{2,10}$') +) where length(cif) between 2 and 10 +order by ora_hash(cif) +fetch first 1000 rows only; +``` + +`order by ora_hash(cif)` da o dispersie **deterministica** (aceeasi de fiecare data), spre +deosebire de `dbms_random`; ordonarea crescuta dupa cod ar fi inclinat lotul spre firme vechi, +deci spre Bucuresti. Suprapunere cu lotul mai vechi de 200: 8 coduri. + +Folosire in proba end-to-end ANAF: + +```powershell +$env:E2E_CODURI = 'D:\ROA\ROADEF\COMUN\utile\Teste\cache_anaf\codes_1000_reale.txt' +$env:E2E_LIMITA = '1000' +```