inline void Assembler::jmpl( Register s1, int simm13a, Register d, RelocationHolder const& rspec ) { insert_nop_after_cbcond(); cti(); emit_data( op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec); has_delay_slot(); }
inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d, RelocationHolder const& rspec) { emit_data( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec); }
inline void Assembler::call( address d, relocInfo::relocType rt ) { insert_nop_after_cbcond(); cti(); emit_data( op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rt); has_delay_slot(); assert(rt != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec"); }
inline void Assembler::flush( Register s1, int simm13a) { emit_data( op(arith_op) | op3(flush_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::bp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt ) { v9_only(); insert_nop_after_cbcond(); cti(); emit_data( op(branch_op) | annul(a) | cond(c) | op2(bp_op2) | branchcc(cc) | predict(p) | wdisp(intptr_t(d), intptr_t(pc()), 19), rt); has_delay_slot(); }
inline void Assembler::cbcond(Condition c, CC cc, Register s1, int simm5, Label& L) { cti(); no_cbcond_before(); emit_data(op(branch_op) | cond_cbcond(c) | op2(bpr_op2) | branchcc(cc) | wdisp10(intptr_t(target(L)), intptr_t(pc())) | rs1(s1) | immed(true) | simm(simm5, 5)); }
inline void Assembler::bpr( RCondition c, bool a, Predict p, Register s1, address d, relocInfo::relocType rt ) { v9_only(); insert_nop_after_cbcond(); cti(); emit_data( op(branch_op) | annul(a) | cond(c) | op2(bpr_op2) | wdisp16(intptr_t(d), intptr_t(pc())) | predict(p) | rs1(s1), rt); has_delay_slot(); }
inline void Assembler::rett( Register s1, int simm13a, relocInfo::relocType rt) { cti(); emit_data( op(arith_op) | op3(rett_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rt); has_delay_slot(); }
inline void Assembler::std( Register d, Register s1, int simm13a) { v9_dep(); assert(d->is_even(), "not even"); emit_data( op(ldst_op) | rd(d) | op3(std_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::swap( Register s1, int simm13a, Register d) { v9_dep(); emit_data( op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::stx( Register d, Register s1, int simm13a) { v9_only(); emit_data( op(ldst_op) | rd(d) | op3(stx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::stf( FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a) { emit_data( op(ldst_op) | fd(d, w) | alt_op3(stf_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::sethi( int imm22a, Register d, RelocationHolder const& rspec ) { emit_data( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(imm22a), rspec); }
inline void Assembler::ldxfsr( Register s1, int simm13a) { v9_only(); emit_data( op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::br( Condition c, bool a, address d, relocInfo::relocType rt ) { v9_dep(); insert_nop_after_cbcond(); cti(); emit_data( op(branch_op) | annul(a) | cond(c) | op2(br_op2) | wdisp(intptr_t(d), intptr_t(pc()), 22), rt); has_delay_slot(); }
inline void Assembler::ldub( Register s1, int simm13a, Register d) { emit_data( op(ldst_op) | rd(d) | op3(ldub_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
Socks5::Socks5(Settings s, Logger *lp, Poller *poller) : Emitter(lp), settings(s), conn(settings["family"].c_str(), settings["socks5_address"].c_str(), settings["socks5_port"].c_str(), lp, poller), proxy_address(settings["socks5_address"]), proxy_port(settings["socks5_port"]) { logger->debug("socks5: connecting to Tor at %s:%s", settings["socks5_address"].c_str(), settings["socks5_port"].c_str()); // Step #0: Steal "error", "connect", and "flush" handlers conn.on_error([this](Error err) { emit_error(err); }); conn.on_connect([this]() { conn.on_flush([]() { // Nothing }); // Step #1: send out preferred authentication methods logger->debug("socks5: connected to Tor!"); Buffer out; out.write_uint8(5); // Version out.write_uint8(1); // Number of methods out.write_uint8(0); // "NO_AUTH" meth. conn.send(out); logger->debug("socks5: >> version=5"); logger->debug("socks5: >> number of methods=1"); logger->debug("socks5: >> NO_AUTH (0)"); // Step #2: receive the allowed authentication methods conn.on_data([this](Buffer d) { buffer << d; auto readbuf = buffer.readn(2); if (readbuf == "") { return; // Try again after next recv() } logger->debug("socks5: << version=%d", readbuf[0]); logger->debug("socks5: << auth=%d", readbuf[1]); if (readbuf[0] != 5 || // Reply version readbuf[1] != 0) { // Preferred auth method emit_error(BadSocksVersionError()); return; } // Step #3: ask Tor to connect to remote host Buffer out; out.write_uint8(5); // Version out.write_uint8(1); // CMD_CONNECT out.write_uint8(0); // Reserved out.write_uint8(3); // ATYPE_DOMAINNAME logger->debug("socks5: >> version=5"); logger->debug("socks5: >> CMD_CONNECT (0)"); logger->debug("socks5: >> Reserved (0)"); logger->debug("socks5: >> ATYPE_DOMAINNAME (3)"); auto address = settings["address"]; if (address.length() > 255) { emit_error(SocksAddressTooLongError()); return; } out.write_uint8(address.length()); // Len out.write(address.c_str(), address.length()); // String logger->debug("socks5: >> domain len=%d", (uint8_t)address.length()); logger->debug("socks5: >> domain str=%s", address.c_str()); auto portnum = std::stoi(settings["port"]); if (portnum < 0 || portnum > 65535) { emit_error(SocksInvalidPortError()); return; } out.write_uint16(portnum); // Port logger->debug("socks5: >> port=%d", portnum); conn.send(out); // Step #4: receive Tor's response conn.on_data([this](Buffer d) { buffer << d; if (buffer.length() < 5) { return; // Try again after next recv() } auto peekbuf = buffer.peek(5); logger->debug("socks5: << version=%d", peekbuf[0]); logger->debug("socks5: << reply=%d", peekbuf[1]); logger->debug("socks5: << reserved=%d", peekbuf[2]); logger->debug("socks5: << atype=%d", peekbuf[3]); // TODO: Here we should process peekbuf[1] more // carefully to map to the error that occurred // and report it correctly to the caller if (peekbuf[0] != 5 || // Version peekbuf[1] != 0 || // Reply peekbuf[2] != 0) { // Reserved emit_error(SocksGenericError()); return; } auto atype = peekbuf[3]; // Atype size_t total = 4; // Version .. Atype size if (atype == 1) { total += 4; // IPv4 addr size } else if (atype == 3) { total += 1 // Len size + peekbuf[4]; // String size } else if (atype == 4) { total += 16; // IPv6 addr size } else { emit_error(SocksGenericError()); return; } total += 2; // Port size if (buffer.length() < total) { return; // Try again after next recv() } buffer.discard(total); // // Step #5: we are now connected // Restore the original hooks // Tell upstream we are connected // If more data, pass it up // conn.on_data([this](Buffer d) { emit_data(d); }); conn.on_flush([this]() { emit_flush(); }); emit_connect(); // Note that emit_connect() may have called close() if (!isclosed && buffer.length() > 0) { emit_data(buffer); } }); }); }); }