Doc
This commit is contained in:
51
README.md
Normal file
51
README.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# Chrome's Hammer
|
||||||
|
|
||||||
|
A Chrome App that runs a local SOCKS5 proxy on `127.0.0.1:1080`, routing traffic through Chrome's networking stack.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Go to `chrome://extensions/`
|
||||||
|
2. Enable "Developer mode"
|
||||||
|
3. Click "Load unpacked"
|
||||||
|
4. Select this folder
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### curl
|
||||||
|
```bash
|
||||||
|
curl --socks5 127.0.0.1:1080 https://httpbin.org/ip
|
||||||
|
```
|
||||||
|
|
||||||
|
### ssh
|
||||||
|
```bash
|
||||||
|
ssh -o ProxyCommand="nc -X 5 -x 127.0.0.1:1080 %h %p" user@host
|
||||||
|
```
|
||||||
|
|
||||||
|
### perl
|
||||||
|
```perl
|
||||||
|
use IO::Socket::SOCKS;
|
||||||
|
my $sock = IO::Socket::SOCKS->new(
|
||||||
|
ProxyAddr => '127.0.0.1',
|
||||||
|
ProxyPort => 1080,
|
||||||
|
ConnectAddr => 'httpbin.org',
|
||||||
|
ConnectPort => 80
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### nodejs
|
||||||
|
```bash
|
||||||
|
npm install socks-proxy-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { SocksProxyAgent } = require('socks-proxy-agent');
|
||||||
|
const agent = new SocksProxyAgent('socks5://127.0.0.1:1080');
|
||||||
|
|
||||||
|
fetch('https://httpbin.org/ip', { agent })
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(console.log);
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
Chrome's Hammer acts as a true SOCKS5 proxy server, creating bidirectional TCP tunnels between your applications and destination servers through Chrome's networking.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Chrome App - SOCKS5 Proxy with Bidirectional Tunneling
|
* Chrome's Hammer - SOCKS5 Proxy with Bidirectional Tunneling
|
||||||
* Supports both HTTP and HTTPS through true SOCKS5 tunneling
|
* Supports both HTTP and HTTPS through true SOCKS5 tunneling
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -367,7 +367,7 @@ function handleDestinationData(destSocketId, data) {
|
|||||||
function setupConnectionHandlers() {
|
function setupConnectionHandlers() {
|
||||||
// Handle new connections from clients
|
// Handle new connections from clients
|
||||||
chrome.sockets.tcpServer.onAccept.addListener(function(acceptInfo) {
|
chrome.sockets.tcpServer.onAccept.addListener(function(acceptInfo) {
|
||||||
console.log('[Proxy] New client connected: ' + acceptInfo.clientSocketId);
|
console.log('[Hammer] New client connected: ' + acceptInfo.clientSocketId);
|
||||||
|
|
||||||
// Initialize SOCKS state for this connection
|
// Initialize SOCKS state for this connection
|
||||||
initConnection(acceptInfo.clientSocketId);
|
initConnection(acceptInfo.clientSocketId);
|
||||||
@@ -378,7 +378,7 @@ function setupConnectionHandlers() {
|
|||||||
|
|
||||||
// Handle accept errors
|
// Handle accept errors
|
||||||
chrome.sockets.tcpServer.onAcceptError.addListener(function(errorInfo) {
|
chrome.sockets.tcpServer.onAcceptError.addListener(function(errorInfo) {
|
||||||
console.error('[Proxy] Accept error:', errorInfo);
|
console.error('[Hammer] Accept error:', errorInfo);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle receive errors
|
// Handle receive errors
|
||||||
@@ -388,9 +388,9 @@ function setupConnectionHandlers() {
|
|||||||
|
|
||||||
// Error code -100 is ERR_CONNECTION_CLOSED - normal disconnect, not an error
|
// Error code -100 is ERR_CONNECTION_CLOSED - normal disconnect, not an error
|
||||||
if (resultCode === -100) {
|
if (resultCode === -100) {
|
||||||
console.log('[Proxy] Socket ' + socketId + ' connection closed');
|
console.log('[Hammer] Socket ' + socketId + ' connection closed');
|
||||||
} else {
|
} else {
|
||||||
console.error('[Proxy] Receive error on socket ' + socketId + ': ' + resultCode);
|
console.error('[Hammer] Receive error on socket ' + socketId + ': ' + resultCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up connections
|
// Clean up connections
|
||||||
@@ -405,7 +405,7 @@ function setupConnectionHandlers() {
|
|||||||
chrome.sockets.tcp.onReceive.addListener(function(receiveInfo) {
|
chrome.sockets.tcp.onReceive.addListener(function(receiveInfo) {
|
||||||
if (receiveInfo.data.byteLength === 0) {
|
if (receiveInfo.data.byteLength === 0) {
|
||||||
var socketId = receiveInfo.socketId;
|
var socketId = receiveInfo.socketId;
|
||||||
console.log('[Proxy] Socket ' + socketId + ' disconnected (EOF)');
|
console.log('[Hammer] Socket ' + socketId + ' disconnected (EOF)');
|
||||||
if (connections[socketId]) {
|
if (connections[socketId]) {
|
||||||
closeConnection(socketId);
|
closeConnection(socketId);
|
||||||
} else if (reverseConnections[socketId]) {
|
} else if (reverseConnections[socketId]) {
|
||||||
@@ -420,13 +420,13 @@ function setupConnectionHandlers() {
|
|||||||
// Check if this is data from a client or destination
|
// Check if this is data from a client or destination
|
||||||
if (connections[socketId]) {
|
if (connections[socketId]) {
|
||||||
// Data from client
|
// Data from client
|
||||||
console.log('[Proxy] Received from client ' + socketId + ': ' + receiveInfo.data.byteLength + ' bytes');
|
console.log('[Hammer] Received from client ' + socketId + ': ' + receiveInfo.data.byteLength + ' bytes');
|
||||||
handleSocksData(socketId, receiveInfo.data);
|
handleSocksData(socketId, receiveInfo.data);
|
||||||
} else if (reverseConnections[socketId]) {
|
} else if (reverseConnections[socketId]) {
|
||||||
// Data from destination
|
// Data from destination
|
||||||
handleDestinationData(socketId, receiveInfo.data);
|
handleDestinationData(socketId, receiveInfo.data);
|
||||||
} else {
|
} else {
|
||||||
console.warn('[Proxy] Received data from unknown socket: ' + socketId);
|
console.warn('[Hammer] Received data from unknown socket: ' + socketId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -434,21 +434,21 @@ function setupConnectionHandlers() {
|
|||||||
function initializeProxy() {
|
function initializeProxy() {
|
||||||
// Prevent double initialization
|
// Prevent double initialization
|
||||||
if (isInitialized) {
|
if (isInitialized) {
|
||||||
console.log('[Proxy] Already initialized or initializing...');
|
console.log('[Hammer] Already initialized or initializing...');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
|
|
||||||
console.log('[Proxy] Initializing Chrome SOCKS Proxy (with tunneling)...');
|
console.log('[Hammer] Initializing Chrome\'s Hammer (with tunneling)...');
|
||||||
|
|
||||||
createServer(PROXY_HOST, PROXY_PORT, function(error, socketId) {
|
createServer(PROXY_HOST, PROXY_PORT, function(error, socketId) {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('[Proxy] Failed to initialize:', error);
|
console.error('[Hammer] Failed to initialize:', error);
|
||||||
isInitialized = false; // Allow retry on failure
|
isInitialized = false; // Allow retry on failure
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[Proxy] SOCKS proxy is running on ' + PROXY_HOST + ':' + PROXY_PORT);
|
console.log('[Hammer] Chrome\'s Hammer is running on ' + PROXY_HOST + ':' + PROXY_PORT);
|
||||||
|
|
||||||
// Setup handlers only once
|
// Setup handlers only once
|
||||||
if (!handlersSetup) {
|
if (!handlersSetup) {
|
||||||
@@ -460,13 +460,13 @@ function initializeProxy() {
|
|||||||
|
|
||||||
// Chrome App lifecycle events
|
// Chrome App lifecycle events
|
||||||
chrome.app.runtime.onLaunched.addListener(function() {
|
chrome.app.runtime.onLaunched.addListener(function() {
|
||||||
console.log('[Proxy] App launched');
|
console.log('[Hammer] App launched');
|
||||||
initializeProxy();
|
initializeProxy();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Chrome App lifecycle - restart when app is restarted
|
// Chrome App lifecycle - restart when app is restarted
|
||||||
chrome.app.runtime.onRestarted.addListener(function() {
|
chrome.app.runtime.onRestarted.addListener(function() {
|
||||||
console.log('[Proxy] App restarted');
|
console.log('[Hammer] App restarted');
|
||||||
// Reset state and reinitialize
|
// Reset state and reinitialize
|
||||||
isListening = false;
|
isListening = false;
|
||||||
isInitialized = false;
|
isInitialized = false;
|
||||||
@@ -476,7 +476,7 @@ chrome.app.runtime.onRestarted.addListener(function() {
|
|||||||
|
|
||||||
// Handle the app window being closed
|
// Handle the app window being closed
|
||||||
chrome.app.window.onClosed.addListener(function() {
|
chrome.app.window.onClosed.addListener(function() {
|
||||||
console.log('[Proxy] App window closed');
|
console.log('[Hammer] App window closed');
|
||||||
// Clean up connections
|
// Clean up connections
|
||||||
for (var socketId in connections) {
|
for (var socketId in connections) {
|
||||||
try {
|
try {
|
||||||
@@ -510,11 +510,11 @@ chrome.alarms.create('keepAlive', { periodInMinutes: 1 });
|
|||||||
chrome.alarms.onAlarm.addListener(function(alarm) {
|
chrome.alarms.onAlarm.addListener(function(alarm) {
|
||||||
if (alarm.name === 'keepAlive') {
|
if (alarm.name === 'keepAlive') {
|
||||||
// Heartbeat: log activity to keep the app alive
|
// Heartbeat: log activity to keep the app alive
|
||||||
console.log('[Proxy] Heartbeat - Proxy is ' + (isListening ? 'active' : 'inactive'));
|
console.log('[Hammer] Heartbeat - Proxy is ' + (isListening ? 'active' : 'inactive'));
|
||||||
|
|
||||||
// Check if server is still listening, restart if needed
|
// Check if server is still listening, restart if needed
|
||||||
if (!isListening && !isInitialized) {
|
if (!isListening && !isInitialized) {
|
||||||
console.log('[Proxy] Server not listening, reinitializing...');
|
console.log('[Hammer] Server not listening, reinitializing...');
|
||||||
initializeProxy();
|
initializeProxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -525,18 +525,18 @@ chrome.alarms.onAlarm.addListener(function(alarm) {
|
|||||||
|
|
||||||
// Handle when app is suspended and resumed
|
// Handle when app is suspended and resumed
|
||||||
chrome.runtime.onSuspend.addListener(function() {
|
chrome.runtime.onSuspend.addListener(function() {
|
||||||
console.log('[Proxy] App being suspended...');
|
console.log('[Hammer] App being suspended...');
|
||||||
});
|
});
|
||||||
|
|
||||||
chrome.runtime.onSuspendCanceled.addListener(function() {
|
chrome.runtime.onSuspendCanceled.addListener(function() {
|
||||||
console.log('[Proxy] Suspend canceled - app is active again');
|
console.log('[Hammer] Suspend canceled - app is active again');
|
||||||
|
|
||||||
// Reinitialize if needed after unsuspend
|
// Reinitialize if needed after unsuspend
|
||||||
if (!isListening) {
|
if (!isListening) {
|
||||||
console.log('[Proxy] Reinitializing after unsuspend...');
|
console.log('[Hammer] Reinitializing after unsuspend...');
|
||||||
isInitialized = false;
|
isInitialized = false;
|
||||||
initializeProxy();
|
initializeProxy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('[Proxy] Background script loaded');
|
console.log('[Hammer] Chrome\'s Hammer background script loaded');
|
||||||
|
|||||||
BIN
icon-128.png
Normal file
BIN
icon-128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
BIN
icon-16.png
Normal file
BIN
icon-16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
BIN
icon-48.png
Normal file
BIN
icon-48.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
114
icon.html
Normal file
114
icon.html
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Chrome's Hammer Icon</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
padding: 40px;
|
||||||
|
background: #f0f0f0;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
.icon-container {
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.instructions {
|
||||||
|
max-width: 600px;
|
||||||
|
background: #e3f2fd;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
h2 { margin-top: 0; }
|
||||||
|
code {
|
||||||
|
background: #f5f5f5;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Chrome's Hammer - Icon Generator</h1>
|
||||||
|
|
||||||
|
<div class="instructions">
|
||||||
|
<h2>How to save the icon:</h2>
|
||||||
|
<ol>
|
||||||
|
<li>Right-click on one of the icons below</li>
|
||||||
|
<li>Select "Save image as..." or take a screenshot</li>
|
||||||
|
<li>Save as <code>icon.png</code> in the chrome_hammer folder</li>
|
||||||
|
<li>For best quality, use the 256x256 size and let Chrome resize it</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="icon-container">
|
||||||
|
<h3>128x128 (Standard)</h3>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" width="128" height="128">
|
||||||
|
<circle cx="64" cy="64" r="60" fill="#4285f4"/>
|
||||||
|
<g fill="#ffffff">
|
||||||
|
<ellipse cx="64" cy="72" rx="35" ry="20"/>
|
||||||
|
<ellipse cx="45" cy="70" rx="20" ry="16"/>
|
||||||
|
<ellipse cx="83" cy="70" rx="20" ry="16"/>
|
||||||
|
<ellipse cx="64" cy="58" rx="25" ry="18"/>
|
||||||
|
<ellipse cx="50" cy="60" rx="15" ry="12"/>
|
||||||
|
<ellipse cx="78" cy="60" rx="15" ry="12"/>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(64, 50) rotate(-30)">
|
||||||
|
<rect x="-4" y="0" width="8" height="35" rx="2" fill="#5f6368"/>
|
||||||
|
<rect x="-12" y="-12" width="24" height="14" rx="2" fill="#ea4335"/>
|
||||||
|
<rect x="-12" y="-12" width="24" height="4" fill="#c5221f"/>
|
||||||
|
<path d="M -8 -12 Q -12 -18 -8 -22 L -4 -18 Z" fill="#ea4335"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="icon-container">
|
||||||
|
<h3>256x256 (High Quality)</h3>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" width="256" height="256">
|
||||||
|
<circle cx="64" cy="64" r="60" fill="#4285f4"/>
|
||||||
|
<g fill="#ffffff">
|
||||||
|
<ellipse cx="64" cy="72" rx="35" ry="20"/>
|
||||||
|
<ellipse cx="45" cy="70" rx="20" ry="16"/>
|
||||||
|
<ellipse cx="83" cy="70" rx="20" ry="16"/>
|
||||||
|
<ellipse cx="64" cy="58" rx="25" ry="18"/>
|
||||||
|
<ellipse cx="50" cy="60" rx="15" ry="12"/>
|
||||||
|
<ellipse cx="78" cy="60" rx="15" ry="12"/>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(64, 50) rotate(-30)">
|
||||||
|
<rect x="-4" y="0" width="8" height="35" rx="2" fill="#5f6368"/>
|
||||||
|
<rect x="-12" y="-12" width="24" height="14" rx="2" fill="#ea4335"/>
|
||||||
|
<rect x="-12" y="-12" width="24" height="4" fill="#c5221f"/>
|
||||||
|
<path d="M -8 -12 Q -12 -18 -8 -22 L -4 -18 Z" fill="#ea4335"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="icon-container">
|
||||||
|
<h3>48x48 (Small)</h3>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" width="48" height="48">
|
||||||
|
<circle cx="64" cy="64" r="60" fill="#4285f4"/>
|
||||||
|
<g fill="#ffffff">
|
||||||
|
<ellipse cx="64" cy="72" rx="35" ry="20"/>
|
||||||
|
<ellipse cx="45" cy="70" rx="20" ry="16"/>
|
||||||
|
<ellipse cx="83" cy="70" rx="20" ry="16"/>
|
||||||
|
<ellipse cx="64" cy="58" rx="25" ry="18"/>
|
||||||
|
<ellipse cx="50" cy="60" rx="15" ry="12"/>
|
||||||
|
<ellipse cx="78" cy="60" rx="15" ry="12"/>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(64, 50) rotate(-30)">
|
||||||
|
<rect x="-4" y="0" width="8" height="35" rx="2" fill="#5f6368"/>
|
||||||
|
<rect x="-12" y="-12" width="24" height="14" rx="2" fill="#ea4335"/>
|
||||||
|
<rect x="-12" y="-12" width="24" height="4" fill="#c5221f"/>
|
||||||
|
<path d="M -8 -12 Q -12 -18 -8 -22 L -4 -18 Z" fill="#ea4335"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
28
icon.svg
Normal file
28
icon.svg
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
|
||||||
|
<!-- Background circle -->
|
||||||
|
<circle cx="64" cy="64" r="60" fill="#4285f4"/>
|
||||||
|
|
||||||
|
<!-- Cloud shape -->
|
||||||
|
<g fill="#ffffff">
|
||||||
|
<!-- Main cloud body -->
|
||||||
|
<ellipse cx="64" cy="72" rx="35" ry="20"/>
|
||||||
|
<ellipse cx="45" cy="70" rx="20" ry="16"/>
|
||||||
|
<ellipse cx="83" cy="70" rx="20" ry="16"/>
|
||||||
|
<ellipse cx="64" cy="58" rx="25" ry="18"/>
|
||||||
|
<ellipse cx="50" cy="60" rx="15" ry="12"/>
|
||||||
|
<ellipse cx="78" cy="60" rx="15" ry="12"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Hammer -->
|
||||||
|
<g transform="translate(64, 50) rotate(-30)">
|
||||||
|
<!-- Hammer handle -->
|
||||||
|
<rect x="-4" y="0" width="8" height="35" rx="2" fill="#5f6368"/>
|
||||||
|
|
||||||
|
<!-- Hammer head -->
|
||||||
|
<rect x="-12" y="-12" width="24" height="14" rx="2" fill="#ea4335"/>
|
||||||
|
<rect x="-12" y="-12" width="24" height="4" fill="#c5221f"/>
|
||||||
|
|
||||||
|
<!-- Hammer claw -->
|
||||||
|
<path d="M -8 -12 Q -12 -18 -8 -22 L -4 -18 Z" fill="#ea4335"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 939 B |
@@ -1,8 +1,13 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "Chrome SOCKS Proxy",
|
"name": "Chrome's Hammer",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Local SOCKS5 proxy that routes requests through Chrome browser",
|
"description": "Local SOCKS5 proxy - routes requests through Chrome's networking",
|
||||||
|
"icons": {
|
||||||
|
"16": "icon-16.png",
|
||||||
|
"48": "icon-48.png",
|
||||||
|
"128": "icon-128.png"
|
||||||
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": ["background.js"]
|
"scripts": ["background.js"]
|
||||||
|
|||||||
Reference in New Issue
Block a user