You are not logged in.
Thank you both. I have not been following ASCII's development as closely as I should
I'm not sure about the answer to my question, but installing these two packages made the issue go away:
libpolkit-backend-1-0-elogind libpolkit-gobject-1-0-elogind
Also, I was having problems mounting/unmounting USB drives (little boxes pop up saying I didn't have permission) and shutdown/rebooting (would take me to login screen) via the GUI. These problems went away when I installed the two packages above.
I thought I'd give ASCII a try and installed it using the Miyo live desktop. Then I installed mate-desktop-environment-extras. Everything works well, but trying to upgrade the system leaves two packages behind:
bruno@thinkpad:~$ sudo apt-get dist-upgrade
[sudo] password for bruno:
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... Done
The following packages have been kept back:
libpolkit-agent-1-0 policykit-1
0 upgraded, 0 newly installed, 0 to remove and 2 not upgraded.
Does anybody know why? The two package versions are version 0.105-9+devuan1.
Devuan has inspired me to do all my computing as simply as possible. Here's a little script I wrote so that I can send email from a script or terminal with virtually zero overhead (specifically, without having to install and configure an MTA such as exim or postfix). All you need is:
1. sudo apt-get install curl
2. put your smtp credentials at the top of the script
3. make this script executable and put it in your PATH (on my system, the script is called easymail)
I thought I'd share it here in case anyone else has use for it. If you see anything in it that could be improved, please let me know.
Cheers,
Bruno
#!/bin/sh
# Purpose: To send email as simply as possible (i.e., without needing to install an MTA
# such as exim or postfix). The script's only dependencies are curl and coreutils on Linux,
# curl and gcoreutils on OpenBSD.
#
# Note about regular vs. root user: Either one can use this script :)
#
# Note about CA ssl certificates on computer/phone:
# If they are missing, add --insecure to the curl command.
#
# Author: Bruno "GNUser" Dantas
# License: GPLv3
# Version: 3.0 (27Mar2019)
# Changelog:
# - working on Devuan ASCII and OpenBSD 6.4
# - body not mandatory
# - no bashisms
# smtp credentials
host='smtps://my.email.com'
port='993'
user='my-username'
password='secretPasswoRd'
main()
{
get_stdin
get_commandline_options "$@"
build_eml_file
wait_for_internet
send_eml_file
}
show_usage()
{
echo "Usage: easymail -d <destination> [-s <subject>] [-b <body>] [-a <attachment>]
Notes:
- destination: an email address (if multiple, precede each one with -d)
- subject: a string
- body: stdin, -b string, or -b file (note: -b flag takes precedence over stdin). examples:
1. echo 'some string' | easymail
2. easymail </path/to/some-text-file
3. easymail -b 'some string'
4. easymail -b /path/to/some-text-file
- attachment: a file (if multiple, precede each one with -a)
Example:
easymail -d somebody@somewhere.com -s 'Devuan' -b 'Devuan rocks!' -a fork.pdf"
}
attach()
{
# create an attachments file if one does not exist yet
[ -z $attachments_file ] && attachments_file=$(mktemp)
# now append the attachment to the attachments file
filename="$(basename "$1")"
echo "------7II5XTH4IPXG2QZOY8LJF98QQX4IR3
Content-Transfer-Encoding: base64
Content-Type: application/octet-stream;
name=\"$filename\"
Content-Disposition: attachment;
filename=\"$filename\";
" >>$attachments_file
if uname | grep -qi BSD; then
cat "$1" | b64encode poop | tail -n +2 >>$attachments_file
else # Linux
cat "$1" | base64 >>$attachments_file
fi
}
cleanup()
{
rm -f $eml_file $attachments_file
}
trap cleanup EXIT HUP TERM INT
get_stdin()
{
if uname | grep -qi BSD; then
body="$(gtimeout 1 dd bs=1 count=1 2>/dev/null && cat)"
else # Linux
body="$(timeout 1 dd bs=1 count=1 2>/dev/null && cat)"
fi
# dd has 1 sec to get 1 byte, which is plenty of time if there is data
# in stdin waiting to be read. If dd succeeds, it passes its byte to stdout
# and triggers cat, which has unlimited time to get remaining data.
# This seems complicated but is necessary: using just cat causes script to
# hang if there is no data in stdin.
}
get_commandline_options()
{
while [ "$#" -gt 0 ]; do
case "$1" in
-d)
curl_destination="${curl_destination}--mail-rcpt $2 "
header_destination="${header_destination}$2, "
shift 2
;;
-s)
subject="$2"
shift 2
;;
-b)
body="$2"
shift 2
;;
-a)
attach "$2"
shift 2
;;
-*)
echo "Invalid option: $1"
shift
;;
*)
shift
;;
esac
done
}
build_eml_file()
{
# create header
eml_file=$(mktemp)
echo "MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=\"----7II5XTH4IPXG2QZOY8LJF98QQX4IR3\"
Content-Transfer-Encoding: 8bit
Subject: $subject
From: Easymail <easymail@suckless.nix>
Date: $(date)
To: $header_destination
------7II5XTH4IPXG2QZOY8LJF98QQX4IR3
Content-Transfer-Encoding: 8bit
Content-Type: text/plain;
charset=UTF-8
" >$eml_file
# append body
if [ -f "$body" ]; then
cat "$body" >>$eml_file
else
echo "$body" >>$eml_file
fi
# append attachment(s) if applicable
if [ -f "$attachments_file" ]; then
cat "$attachments_file" >>$eml_file
fi
}
wait_for_internet()
{
while true; do
wget --spider --timeout=2 -o /dev/null duckduckgo.com && return 0
sleep 1
done
}
send_eml_file()
{
curl --url ${host}:${port} --ssl-reqd --upload-file $eml_file $curl_destination --user ${user}:${password} >/dev/null 2>&1
}
if [ "$#" -le 1 ]; then
show_usage
else
main "$@"
fi
That image is hilarious. So sad but so true.
I had heard dash was faster, didn't know it could be that much faster. Good to know. I'll definitely try avoid bashisms from now on.
Enjoy the scripts, greenjeans! I'm happy to mingle with you here--learn something new every day!
I purged the bashisms and added some polish. Here are the scripts again, tested and working on multiple shells (bash, dash, busybox ash):
#!/bin/sh
# This script should be called "pack". It works as-is for any project.
project_folder="$(dirname "$(realpath "$0")")"
project_name="$(basename "$project_folder")"
cd "$project_folder"
tar cvzf ../payload.tar.gz ./*
cd ..
cat "$project_folder/unpack" payload.tar.gz >"$project_name.run" && chmod a+x "$project_name.run"
mv "$project_name.run" $HOME/Desktop 2>/dev/null
rm payload.tar.gz
printf "$HOME/Desktop/$project_name.run created\n"
exit 0
#!/bin/sh
# This script should be called "unpack". Only the POST-UNPACK COMMAND needs to be customized.
ARCHIVE_STARTLINE=$(awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' "$0") # gets line number below "__ARCHIVE_BELOW__"
if [ "$1" = "unpack" ]; then
runfile_dir="$(dirname "$(realpath "$0")")"
project_name="$(basename "$0" .run)"
DEST_DIR="$runfile_dir/$project_name"; [ -d "$DEST_DIR" ] && rm -r "$DEST_DIR"; mkdir "$DEST_DIR"
tail -n +$ARCHIVE_STARTLINE "$0" | tar xzv -C "$DEST_DIR"
else
export TMPDIR=$(mktemp -d /tmp/selfextract.XXXXXX)
trap "rm -rf $TMPDIR" EXIT HUP TERM INT
tail -n +$ARCHIVE_STARTLINE "$0" | tar xzv -C "$TMPDIR" 1>/dev/null && cd "$TMPDIR"
./foo "$@" # <-- POST-UNPACK COMMAND
fi
exit 0
__ARCHIVE_BELOW__
P.S. Another option would be to ditch the bashisms in the scripts and use a /bin/sh she-bang. Surely all GNU/Linux users would have some shell installed. This would be an easy upgrade.
Nice thought. That hadn't occurred to me, nor could I imagine that some penguinistas might have a problem with bash. Wow, there are some real hard-core minimalists out there!
All of my projects contain binaries in the tarball anyway (with accompanying source code--hence the benefit of user being able to unpack and re-pack the .run file), so using a shell script header does not expand the audience. Therefore, I would only stand to gain by using a binary header instead.
I'll check out using C or newlisp as an alternative when I have a chance. I have a crush on C, but tend to gravitate towards bash and python because I'm lazy. If you can't have the one you love, love the one you're with.
Combining multiple files into a single file is trivial (tar) but is just one of three ingredients. The challenging and fun part was figuring out how to make the tarball self-extracting and self-executing. I thought I'd share how I did it, since it was not trivial and could be useful to someone.
I enjoy putting together little apps for myself or my penguin friends, and have long looked for a simple way to bundle scripts, binaries, and icons. I realize this can be accomplished with a .deb or an AppImage, but I've always longed for something much simpler.
Well, I finally figured something out. It just involves two scripts.
This one should be named "pack":
#!/bin/bash
# no need to change anything in this script (nothing in here is project-specific)
project_folder="$(dirname "$(realpath "$0")")"
project_name="$(basename "$project_folder")"
tar cvzf ../payload.tar.gz ./*
cd ..
cat "$project_folder/unpack" payload.tar.gz >"$project_name.run" && chmod a+x "$project_name.run"
mv "$project_name.run" $HOME/Desktop 2>/dev/null
rm payload.tar.gz
echo "$HOME/Desktop/$project_name.run created"
exit 0
And this one should be named "unpack":
#!/bin/bash
# the only line in this script that you need to customize is the POST-UNPACK COMMAND
ARCHIVE_STARTLINE=`awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' "$0"` # gets line number below "__ARCHIVE_BELOW__"
if [[ "$1" = "unpack" || "$1" = "extract" ]]; then
executable_name="$(basename "$0")"
project_name="${executable_name%.*}" # strip extension
executable_folder="$(dirname "$(realpath "$0")")"
DEST_DIR="$executable_folder/$project_name"; [ -d "$DEST_DIR" ] && rm -r "$DEST_DIR"; mkdir "$DEST_DIR"
tail -n+$ARCHIVE_STARTLINE "$0" | tar xzv -C "$DEST_DIR" &>/dev/null
exit 0
else
export TMPDIR=`mktemp -d /tmp/selfextract.XXXXXX`
tail -n+$ARCHIVE_STARTLINE "$0" | tar xzv -C "$TMPDIR" &>/dev/null
cd "$TMPDIR"
./foo "$@" # <-- POST-UNPACK COMMAND
# cleanup:
cd -
rm -rf "$TMPDIR"
exit 0
fi
__ARCHIVE_BELOW__
Say you have a directory called some-project, which contains shell scripts, binaries, icons, and maybe other things your app needs. Simply put the pack and unpack scripts in the some-project directory. The only thing that needs to be customized is the POST-UNPACK COMMAND line in the unpack script.
Now executing pack will create "some-project.run" on your desktop, which you can use yourself or share with your friends.
Running some-project.run will unpack the some-project directory to /tmp and launch the post-unpack command. If your friend is computer-savvy and wants to inspect and/or change the contents of some-project.run, running some-project.run with "unpack" as an argument will give them the some-project directory so that they can change stuff and then re-pack:
some-project.run unpack # this will create some-project directory
cd some-project
# change stuff in the some-project directory
./pack
P.S. The central idea for all of this was this amazing old post from Jeff Parent. For an example project, check out my portable (no dependencies!) international-keyboard.run.
Just for the fun of it, I went ahead and converted my spare laptop into a router. For the sake of completion and posterity, I want to document here the simplified approach that I took. It really is as easy as 1-2-3:
1. Uninstall or disable network-manager if your soon-to-be router has it (it gets in the way and is not necessary for a machine that gets internet via ethernet)
2. Make sure your /etc/network/interfaces has nothing but this:
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
auto wlan0
iface wlan0 inet static
address 192.168.10.1
netmask 255.255.255.0
dns-nameservers 198.153.192.50
3. Run this script at startup:
#!/bin/bash
# Dependencies: iproute2 iptables dnsmasq hostapd haveged
# Usage: Set the variables below, then run this script as root/sudo
ssid=GNULinuxAP
password=DevuanRocks
ip_stem=192.168.10
dns_server=8.8.8.8
channel=11
main()
{
setup_nat
setup_dnsmasq
setup_hostapd
}
setup_nat()
{
echo 1 >/proc/sys/net/ipv4/conf/eth0/forwarding
echo 1 >/proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
}
setup_dnsmasq()
{
ifconfig wlan0 $ip_stem.1
echo "listen-address=$ip_stem.1
bind-dynamic
dhcp-range=$ip_stem.100,$ip_stem.200,255.255.255.0,24h
dhcp-option-force=option:router,$ip_stem.1
dhcp-option-force=option:dns-server,$dns_server
dhcp-option-force=option:mtu,1500
no-hosts" >/tmp/dnsmasq.conf
dnsmasq -C /tmp/dnsmasq.conf
}
setup_hostapd()
{
echo "beacon_int=100
ssid=$ssid
interface=wlan0
driver=nl80211
channel=$channel
ignore_broadcast_ssid=0
ap_isolate=0
hw_mode=g
wpa=3
wpa_passphrase=$password
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP CCMP
rsn_pairwise=CCMP" >/tmp/hostapd.conf
hostapd /tmp/hostapd.conf
}
main
That's it!
As you can see, without network-manager and without the need to create a virtual hotspot interface (since eth0 is being used to get internet, wlan0 itself can be used as the hotspot interface), the whole thing becomes rather simple.
(BTW, I dug around my Netgear router running LibreCMC and found that both dnsmasq and hostapd were running--my guess is that a lot of linux-based routers follow exactly the above approach.)
You're welcome, greenjeans. Enjoy! One of my favorite things about GNU/Linux is definitely the fact that it can make older hardware useful again.
I discovered that NetworkManager can be dealt with without requiring reboot or a service restart. I updated my script and the create_ap instructions accordingly (i.e., removed the step where user needs to bother with this).
Also, I cooked up a different "fake" mac address for the virtual hotspot interface, this one using same vendor bits as my Netgear router. Hopefully Netgear read the rules when they chose their vendor bits.
Finally, I made miscellaneous improvements to my script. It is tested and working reliably in Devuan Jessie, Debian Jessie, and Trisquel7-mini. (As a side note, each of these three is running its default init: SysVinit, systemd, and Upstart, respectively. In fact, I found that even though Trisquel7-mini officially runs Upstart, it has bits and pieces of SysVinit and systemd thrown in. What a mess! I'm so happy with Devuan!).
So to summarize (and assuming you want to use my version of the script ):
0. Check that your wireless network card offers AP mode (see post #1)
1. Install the dependencies
2. Copy the script in post #2 into a file (hotspot might be a good name for the file!)
3. Make the file executable
4. sudo hotspot
Stopping the script (e.g., with Control + c) turns off the hotspot and cleans everything up.
When my Netgear WNDR3800 router running LibreCMC dies, I think I'll just use this script on my old EeePC to repurpose it as a vpn router.
I hope someone out there finds this script as tremendously useful as I do
See this tool: https://macvendors.com/
5c:ac:4c are vendor bits of a real vendor (Hon Hai)
5e:ac:4c do not match any existing vendor bits.
I guess Hon Hai didn't follow the rules. I'll stick with the naughty but plausible/existing vendor bits.
That's weird, because the vendor bits of that made-up mac address are the same as that in my atheros wifi card. I adjusted the made-up address as you recommended, but I'm going to check that the vendor bits 5e:ac:4c match some vendor. I want the mac to be plausible.
@ralph.ronnquist - Good instinct. Yes, that's all that was needed. This seems to be the slow step:
iw dev wlan0 interface add ap0 type __ap
So putting the sleep 1 immediately after it cured all ills. I've updated my skinny version accordingly.
Thanks a bundle!
Good thought. Alas, I tried it and it still happens randomly. Here's an example:
bruno@thinkpad:~$ sudo bash -x hotspot
+ hotspot_ssid=FreeInternet
+ hotspot_password=DevuanRules
++ route
++ wc -l
++ grep default
++ awk '{print $8}'
+ n_candidates=1
+ '[' 1 = 1 ']'
++ route
++ awk '{print $8}'
++ grep default
+ internet_if=wlan0
+ iw dev wlan0 interface add ap0 type __ap
+ ip link set dev ap0 address 5c:ac:4c:2f:93:60
+ ip link set down dev ap0
+ ip addr flush ap0
+ sleep 1
+ ip link set up dev ap0
RTNETLINK answers: Name not unique on network
+ ip addr add 192.168.20.1/24 broadcast 192.168.20.255 dev ap0
+ cat /proc/sys/net/ipv4/conf/wlan0/forwarding
+ cat /proc/sys/net/ipv4/ip_forward
+ echo 1
+ echo 1
+ modprobe nf_nat_pptp
+ iptables -w -t nat -I POSTROUTING -s 192.168.20.0/24 '!' -o ap0 -j MASQUERADE
+ iptables -w -I FORWARD -i ap0 -s 192.168.20.0/24 -j ACCEPT
+ iptables -w -I FORWARD -i wlan0 -d 192.168.20.0/24 -j ACCEPT
+ iptables -w -I INPUT -p tcp -m tcp --dport 5353 -j ACCEPT
+ iptables -w -I INPUT -p udp -m udp --dport 5353 -j ACCEPT
+ iptables -w -t nat -I PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 5353
+ iptables -w -t nat -I PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 5353
+ iptables -w -I INPUT -p udp -m udp --dport 67 -j ACCEPT
+ echo 'listen-address=192.168.20.1
bind-dynamic
dhcp-range=192.168.20.100,192.168.20.200,255.255.255.0,24h
dhcp-option-force=option:router,192.168.20.1
dhcp-option-force=option:dns-server,192.168.20.1
# If you’d like to have dnsmasq assign static IPs, bind the LAN computer'\''s
# NIC MAC address:
#dhcp-host=98:f1:70:4f:4b:67,192.168.20.60 # roku stick
dhcp-option-force=option:mtu,1500
no-hosts'
+ dnsmasq -C /tmp/dnsmasq.conf -p 5353
++ iw dev wlan0 link
++ awk '{print $2}'
++ grep -i freq
+ frequency=2462
+ '[' -z 2462 ']'
++ ieee80211_frequency_to_channel 2462
++ local FREQ=2462
++ [[ 2462 -eq 2484 ]]
++ [[ 2462 -lt 2484 ]]
++ echo 11
+ channel=11
+ echo 'beacon_int=100
ssid=FreeInternet
interface=ap0
driver=nl80211
channel=11
ignore_broadcast_ssid=0
ap_isolate=0
hw_mode=g
wpa=3
wpa_passphrase=DevuanRules
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP CCMP
rsn_pairwise=CCMP'
+ hostapd /tmp/hostapd.conf
Configuration file: /tmp/hostapd.conf
Could not set interface ap0 flags (UP): Name not unique on network
nl80211: Could not set interface 'ap0' UP
nl80211 driver initialization failed.
hostapd_free_hapd_data: Interface ap0 wasn't started
+ trap cleanup EXIT HUP TERM
+ cleanup
+ echo 'Cleaning up...'
Cleaning up...
+ cat /tmp/forwarding.saved
+ cat /tmp/ip_forward.saved
+ pkill hostapd
+ iptables -w -t nat -D POSTROUTING -s 192.168.20.0/24 '!' -o ap0 -j MASQUERADE
+ iptables -w -D FORWARD -i ap0 -s 192.168.20.0/24 -j ACCEPT
+ iptables -w -D FORWARD -i wlan0 -d 192.168.20.0/24 -j ACCEPT
+ iptables -w -D INPUT -p tcp -m tcp --dport 5353 -j ACCEPT
+ iptables -w -D INPUT -p udp -m udp --dport 5353 -j ACCEPT
+ iptables -w -t nat -D PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 5353
+ iptables -w -t nat -D PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 5353
+ iptables -w -D INPUT -p udp -m udp --dport 67 -j ACCEPT
+ ip link set down dev ap0
+ ip addr flush ap0
+ iw dev ap0 del
Any other ideas? It would be nice to get the skinny version working reliably.
The only quirk with my skinny version is that sometimes (apparently randomly) at this point in the script:
ip link set up dev ap0
I get this error:
RTNETLINK answers: Name not unique on network
This happens randomly and I really can't account for it. Sometimes it happens even after a reboot, so I'm 100% sure that the name ap0 is unique on the network. I'd hate to put 1700 lines of code back in just for this. Any idea how to troubleshoot this?
Over the past few days I've been dissecting create_ap (over 1800 lines) to see how it works. So far, I've managed to cut it down to about 150 lines by hard-wiring some sensible defaults and eliminating myriad sanity checks. Here is my skinny version:
#!/bin/bash
# Dependencies: iw iproute2 iptables dnsmasq hostapd haveged
# Usage: Set the ssid and password below, then run this script as root/sudo on host machine
# Result: A virtual wireless interface is created on host to share its internet access
hotspot_ssid=GNULinuxAP
hotspot_password=gnuforever
main()
{
shoo_network_manager
find_internet_if
find_wireless_if
create_hotspot_if
setup_nat
setup_dnsmasq
setup_hostapd
}
shoo_network_manager() # if network manager is running, make sure it doesn't meddle with our hostpot (we don't need its "help")
{
if pgrep NetworkManager &>/dev/null; then # network manager is running
nm_config_file=/etc/NetworkManager/NetworkManager.conf
if grep -q 'interface-name:ap0' $nm_config_file; then # ap0 already mentioned in config file, so we're done
return
else # network manager is running and ap0 not mentioned in config file
if grep -q 'unmanaged-devices' $nm_config_file; then # there's an unmanaged interface list already, add ap0 to it
sed -i -r 's/(unmanaged-devices.*$)/\1;interface-name:ap0/' $nm_config_file
else # there's no unmanaged interface list yet, so let's start one
printf '\n[keyfile]\nunmanaged-devices=interface-name:ap0' >>$nm_config_file
fi
fi
fi
}
find_internet_if() # find host's internet-facing interface
{
n_candidates=$(route | grep default | awk '{print $8}' | wc -l)
if [ "$n_candidates" = "1" ]; then
internet_if=$(route | grep default | awk '{print $8}')
else
echo "More than one internet-facing interface found: $(route | grep default | awk '{print $8}')"
echo -n "Which one should will feed the hotspot? "
read internet_if
fi
}
find_wireless_if() # find host's wireless interface
{
wireless_if=$(cat /proc/net/wireless | perl -ne '/(\w+):/ && print $1') # e.g., wlan0 or wlp2s0
}
create_hotspot_if() # create a virtual wireless interface to use as hotspot, with arbitrary name of ap0
{
iw dev $wireless_if interface add ap0 type __ap
# wait up to 5 seconds for ap0 to exist
c=0
while true; do
iw dev ap0 info &>/dev/null && break
sleep 0.5
((c++))
((c==10)) && { echo "ap0 could not be created within the time limit."; exit 1; }
done
sleep 1
ip link set dev ap0 address c4:04:15:9c:07:9d # a made-up mac address with real vendor bits (c4:04:15 = Netgear)
ip link set down dev ap0
ip addr flush ap0
ip link set up dev ap0
ip addr add 192.168.20.1/24 broadcast 192.168.20.255 dev ap0
}
setup_nat() # nat is more robust than bridge
{
# first save current routing settings
cat /proc/sys/net/ipv4/conf/$internet_if/forwarding >/tmp/forwarding.saved
cat /proc/sys/net/ipv4/ip_forward >/tmp/ip_forward.saved
# now go ahead and change routing/firewall settings for NAT sharing
echo 1 >/proc/sys/net/ipv4/conf/$internet_if/forwarding
echo 1 >/proc/sys/net/ipv4/ip_forward
modprobe nf_nat_pptp &>/dev/null # to enable clients to establish PPTP connections
iptables -w -t nat -I POSTROUTING -s 192.168.20.0/24 ! -o ap0 -j MASQUERADE
iptables -w -I FORWARD -i ap0 -s 192.168.20.0/24 -j ACCEPT
iptables -w -I FORWARD -i $internet_if -d 192.168.20.0/24 -j ACCEPT
iptables -w -I INPUT -p tcp -m tcp --dport 5353 -j ACCEPT # for dns, can be any non-privileged port
iptables -w -I INPUT -p udp -m udp --dport 5353 -j ACCEPT
iptables -w -t nat -I PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 5353
iptables -w -t nat -I PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 5353
iptables -w -I INPUT -p udp -m udp --dport 67 -j ACCEPT
}
setup_dnsmasq() # DHCP server
{
echo "listen-address=192.168.20.1
bind-dynamic
dhcp-range=192.168.20.100,192.168.20.200,255.255.255.0,24h
dhcp-option-force=option:router,192.168.20.1
dhcp-option-force=option:dns-server,192.168.20.1
dhcp-option-force=option:mtu,1500
no-hosts" >/tmp/dnsmasq.conf
dnsmasq -C /tmp/dnsmasq.conf -p 5353
}
ieee80211_frequency_to_channel()
{
local FREQ=$1
if [[ $FREQ -eq 2484 ]]; then
echo 14
elif [[ $FREQ -lt 2484 ]]; then
echo $(( ($FREQ - 2407) / 5 ))
elif [[ $FREQ -ge 4910 && $FREQ -le 4980 ]]; then
echo $(( ($FREQ - 4000) / 5 ))
elif [[ $FREQ -le 45000 ]]; then
echo $(( ($FREQ - 5000) / 5 ))
elif [[ $FREQ -ge 58320 && $FREQ -le 64800 ]]; then
echo $(( ($FREQ - 56160) / 2160 ))
else
echo 0
fi
}
setup_hostapd()
{
# first figure out radio frequency/channel for hotspot
frequency=$(iw dev $wireless_if link | grep -i freq | awk '{print $2}')
if [ -z "$frequency" ]; then # if wifi is off, use an arbitary channel (can be 1 or any other)
channel=1
else # if wifi is active on host, put ap0 on same channel for maximum hardware compatibility
channel=$(ieee80211_frequency_to_channel $frequency)
fi
# now we have everything we need for hostapd
echo "beacon_int=100
ssid=$hotspot_ssid
interface=ap0
driver=nl80211
channel=$channel
ignore_broadcast_ssid=0
ap_isolate=0
hw_mode=g
wpa=3
wpa_passphrase=$hotspot_password
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP CCMP
rsn_pairwise=CCMP" >/tmp/hostapd.conf
hostapd /tmp/hostapd.conf
}
cleanup()
{
echo "Cleaning up..."
cat /tmp/forwarding.saved >/proc/sys/net/ipv4/conf/$internet_if/forwarding
cat /tmp/ip_forward.saved >/proc/sys/net/ipv4/ip_forward
pkill -f /tmp/dnsmasq.conf # kill only the dnsmasq instance we started
pkill hostapd
iptables -w -t nat -D POSTROUTING -s 192.168.20.0/24 ! -o ap0 -j MASQUERADE
iptables -w -D FORWARD -i ap0 -s 192.168.20.0/24 -j ACCEPT
iptables -w -D FORWARD -i $internet_if -d 192.168.20.0/24 -j ACCEPT
iptables -w -D INPUT -p tcp -m tcp --dport 5353 -j ACCEPT
iptables -w -D INPUT -p udp -m udp --dport 5353 -j ACCEPT
iptables -w -t nat -D PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 5353
iptables -w -t nat -D PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 5353
iptables -w -D INPUT -p udp -m udp --dport 67 -j ACCEPT
ip link set down dev ap0
ip addr flush ap0
iw dev ap0 del
}
trap cleanup EXIT HUP TERM
main
P.S. Both create_ap and my script have a pretty thorough cleanup function. But if you're paranoid, just reboot after using the hotspot and you'll be guaranteed to be 100% back to your pre-hotspot network settings.
I found create_ap and it's so cool that I thought I'd tell all my Devuan friends about it It works similarly to the "Hotspot" function on Android phones and is free software (FreeBSD license).
0. Before proceeding, make sure your wireless card supports AP (access point) mode. You want to see "AP" listed when you run "iw list" in a terminal:
bruno@thinkpad:~$ iw list
Wiphy phy0
---snip---
Supported interface modes:
* IBSS
* managed
* AP
1. To get all create_ap's dependencies:
sudo apt-get util-linux procps hostapd iproute2 iw iwconfig haveged
2. Last step is to get create_ap itself from their github page. To "install" it, just download the zip from github, extract it, then run sudo make install from the root of the extracted folder. Nothing is actually compiled--the make command simply copies some things over to /usr/bin. To uninstall, running sudo make uninstall from the root of the extracted folder removes everything.
---
Now enjoy all the options this opens up:
If you have a laptop connected to wifi and want to use the laptop as a wifi repeater (yes, this actually works with a single wireless adapter):
create_ap wlan0 wlan0 MyAccessPoint MyPassPhrase
If you have a laptop connected to ethernet that you want to use as a router:
create_ap wlan0 eth0 MyAccessPoint MyPassPhrase
If you have a laptop connected to ethernet and running openvpn that you want to use as a vpn router:
create_ap wlan0 tun0 MyAccessPoint MyPassPhrase
Amazing, right?
Hello, oui. I used ibus for years, but was annoyed by some buggy behavior and now I only use a python/bash script I wrote. The script allows you to use custom two-character combinations to trigger unicode characters (e.g., a` triggers à and c; triggers ç). One could expand the script to also have 3+ character triggers if this were necessary.
You just install the handful of dependencies, customize the script with your unicode characters and triggers, run the script, and start typing. Script changes nothing on your machine and leaves no trace when you stop it from its taskbar icon.
I realize that for a language like Chinese something like my script isn't going to work given that you'd need to define triggers for thousands of unicode characters, but depending on the language (e.g., for French) it might be a nice option.
Thanks, ralph.ronnquist. I'll explore that option.
In the meantime, I found yet another gem. Here is a python script that sends a signal to somescript whenever there is any mouse or keyboard activity:
from pynput import keyboard
from pynput import mouse
import os
def send_signal()
os.system('pkill -USR1 somescript')
def on_press(key):
send_signal()
def on_move(x, y):
send_signal()
def on_click(x, y, button, pressed):
send_signal()
def on_scroll(x, y, dx, dy):
send_signal()
with mouse.Listener(on_move=on_move, on_click=on_click, on_scroll=on_scroll) as listener:
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
It would be easy to adapt the above to only send the signal in a subset of cases (e.g., only on left clicks).
I couldn't find anything suitable, so I rolled my own alternative to ibus. It's a simple bash script that allows typing diacritic either before or after the letter, user's choice. The script does not use "preedit text", so no characters ever disappear.
Getting the dependencies:
sudo apt-get install xvkbd python3 && sudo pip3 install pynput
You also need to install yad, which is not in the Devuan Jessie repositories but is easy to find (e.g., by clicking on your architecture at the bottom of this page).
pynput didn't work for me at first because one of its dependencies, the "six" module, was outdated. So, to be safe:
sudo pip3 install --upgrade six
Well, here's the script. It should "just work" once you have all the dependencies. You only need to alter it if you want to add or change the special characters section.
#!/bin/bash
# International keyboard (alternative to ibus for x11)
# Author: Bruno "GNUser" Dantas
# License: GPLv3
# Dependencies:
# sudo apt-get install xvkbd python3 yad
# sudo pip3 install pynput
# Usage:
# - Change the triggers and unicode sequences in "watch_for_triggers" function to suit your needs
# - Run this script as regular user to turn on the international keyboard
# - Stop the script--via taskbar icon or, if running in terminal, Control+c--to clean up without a trace
main()
{
create_pipe
create_keylogger # writes to pipe
create_taskbar_icon
watch_for_triggers # reads from pipe, replaces user-defined character combinations with unicode characters
}
create_pipe()
{
pipe=/tmp/international
rm -f $pipe
mkfifo $pipe
exec 3<>$pipe
}
create_keylogger()
{
# to troubleshoot the keylogger:
# 1. copy the python code below into a file foo
# 2. comment out the three fifo lines, uncomment the print line in log_it function
# 3. in a terminal: python3 /path/to/foo
# 4. type stuff outside the terminal and watch terminal
echo "
from pynput import keyboard
from pynput import mouse
import os
fifo_write = open('$pipe', 'w')
def log_it(output):
fifo_write.write(output + '\n')
fifo_write.flush()
#print(output)
# get initial capslock state
exit_code = os.system('''xset q 2>/dev/null | grep -q -E 'Caps Lock: +on' ''')
if exit_code == 0:
capslock_in_effect = True
else:
capslock_in_effect = False
# this function runs each time a key is pressed:
def on_press(key):
global capslock_in_effect
output = str(key)
if output == 'Key.caps_lock': # if capslock pressed, toggle capslock state
capslock_in_effect = not capslock_in_effect
if not output.startswith('Key'): # special keys start with 'Key' and can be logged as-is
output = output[1:-1] # remove quotes around character
if capslock_in_effect:
output = output.swapcase()
if not output.startswith('Key.shift'): # don't log shift keys (e.g., while loop expects a~ not aKey.shift~)
log_it(output)
# this function runs each time a mouse button is pressed:
def on_click(x, y, button, pressed):
button = str(button)
if pressed and button == 'Button.left':
log_it('Key.mousebutton_left')
# start listening
with mouse.Listener(on_click=on_click) as listener:
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
" >/tmp/tiny-keylogger
python3 /tmp/tiny-keylogger &
}
echo "$(basename $0)" >/tmp/scriptname # so cleanup function can find this script's name when called from yad
cleanup()
{
echo "Cleaning up..."
pkill -f International # kill taskbar icon
pkill -f tiny-keylogger # kill keylogger
pkill -KILL "$(cat /tmp/scriptname)" # kill this script
}
trap cleanup EXIT HUP TERM INT
create_taskbar_icon()
{
export -f cleanup
yad --notification --image='accessories-character-map' --text='International Keyboard' \
--no-middle --menu="Stop!bash -c cleanup" --command='' &
}
replace()
{
xvkbd -xsendevent -text "\b\b\[U$1]" # send two backspaces then desired unicode character
}
watch_for_triggers()
{
# endless loop (it reads from a fifo pipe, so never encounters EOF)
while read current_char; do
echo "${previous_char}${current_char}" # for debugging while running in terminal
case "${previous_char}${current_char}" in
# Portuguese
'A`') replace 00C0;;
'a`') replace 00E0;;
"A'") replace 00C1;;
"a'") replace 00E1;;
'A^') replace 00C2;;
'a^') replace 00E2;;
'A~') replace 00C3;;
'a~') replace 00E3;;
"E'") replace 00C9;;
"e'") replace 00E9;;
'E^') replace 00CA;;
'e^') replace 00EA;;
"I'") replace 00CD;;
"i'") replace 00ED;;
'O`') replace 00D2;;
'o`') replace 00F2;;
"O'") replace 00D3;;
"o'") replace 00F3;;
'O^') replace 00D4;;
'o^') replace 00F4;;
'O~') replace 00D5;;
'o~') replace 00F5;;
"U'") replace 00DA;;
"u'") replace 00FA;;
'U;') replace 00DC;;
'u;') replace 00FC;;
'C;') replace 00C7;;
'c;') replace 00E7;;
# Esperanto
'Cx') replace 0108;;
'CX') replace 0108;;
'cx') replace 0109;;
'Gx') replace 011C;;
'GX') replace 011C;;
'gx') replace 011D;;
'Hx') replace 0124;;
'HX') replace 0124;;
'hx') replace 0125;;
'Jx') replace 0134;;
'JX') replace 0134;;
'jx') replace 0135;;
'Sx') replace 015C;;
'SX') replace 015C;;
'sx') replace 015D;;
'Ux') replace 016C;;
'UX') replace 016C;;
'ux') replace 016D;;
esac
previous_char=$current_char
done <&3
}
main
@fsmithred - If you just need your system to do something for you (e.g., stop a script) when coming out of idle (i.e., when there is any keyboard or mouse activity), you may like this: https://unix.stackexchange.com/a/122816
I tried it and it worked like a charm. I just needed to install libxss-dev (provides scrnsaver.h) before compiling.