In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces the relevant knowledge of "how node.js supports multi-user web terminals". The editor shows you the operation process through an actual case. The operation method is simple, fast and practical. I hope this article "how node.js supports multi-user web terminals" can help you solve the problem.
Terminal (command line), as a common function of local IDE, has a very strong support for project git operation and file operation. For WebIDE, in the case of no web pseudo terminal, only providing encapsulated command line interface is not enough for developers to use, so for a better user experience, the development of web pseudo terminal is also put on the agenda.
Investigation and research
Terminals, in our understanding, are slightly similar to command-line tools, and generally speaking, they can execute the process of shell. Each time you enter a series of commands on the command line and enter enter, the terminal process will fork a child process to execute the input command. The terminal process will listen for the exit of the child process through the system call wait4 () and output the execution information of the child process through the exposed stdout.
If we implement a terminal function similar to localization on the web side, we may need to do more: network delay and reliability guarantee, shell user experience as close as possible to localization, web terminal UI width and height adaptation to output information, security admission control and rights management, and so on. Before the specific implementation of the web terminal, we need to evaluate which of these functions are the most core, and it is clear: the functional implementation of shell and user experience, security (web terminal is a function provided by the online server, so security must be guaranteed). Only on the premise of ensuring these two functions can the web pseudo-terminal be officially online.
First of all, consider the technical implementation of these two functions (server-side technology adopts nodejs):
Node native module provides a repl module, it can be used to achieve interactive input and output, while providing tab completion function, custom output style and other functions, but it can only execute node-related commands, so we want to execute the system shell native module child_porcess, it provides spawn this encapsulated the underlying libuv uv_spawn function, the underlying execution system calls fork and execvp, execute shell commands. However, it does not provide other features of the pseudo terminal, such as tab automatic completion, key display history commands and other operations.
Therefore, it is impossible to realize a pseudo terminal by using the native module of node on the server side, so we need to continue to explore the principle of the pseudo terminal and the implementation direction of the node side.
Pseudo terminal
A pseudo terminal is not a real terminal, but a "service" provided by the kernel. Terminal Services usually consists of three layers:
The top level provides the input and output interface of the character device, the line specification (line discipline) in the middle layer, and the underlying hardware driver.
Among them, the top interface is often implemented through system call functions, such as (read,write), while the underlying hardware driver is responsible for the master-slave device communication of the pseudo terminal, which is provided by the kernel. The line discipline looks more abstract, but in fact, functionally, it is responsible for the "processing" of input and output information, such as dealing with interrupt characters (ctrl + c) and some fallback characters (backspace and delete) in the input process, while converting the output newline n to rn and so on.
A pseudo terminal is divided into two parts: the master device and the slave device, whose underlying layer is connected by a two-way pipeline (hardware driver) that implements the default line protocol. Any input from the pseudo-terminal master device is reflected on the slave device and vice versa. The output information of the slave device is also sent to the master device through the pipeline, so that the shell can be executed in the slave device of the pseudo terminal to complete the function of the terminal.
The slave device of the pseudo terminal can truly simulate the tab completion of the terminal and other shell special commands, so under the premise that the node native module can not meet the needs, we need to look at the bottom to see what functions OS provides. Currently, the glibc library provides posix_openpt interfaces, but the process is a bit cumbersome:
Use posix_openpt to open a pseudo-terminal master device grantpt set the permissions of the slave device unlockpt unlock the corresponding slave device get the slave device name (similar to / dev/pts/123) master (slave) device read and write, and perform the operation
As a result, a better encapsulated pty library has emerged, and all of these functions can be achieved with just one forkpty function. Through the preparation of a node C++ expansion module, with the pty library to achieve a pseudo-terminal slave device command line execution terminal.
The issue of pseudo-terminal security is discussed at the end of the article.
The idea of realizing pseudo-terminal
According to the characteristics of the master-slave device of the pseudo-terminal, we manage the life cycle and resources of the pseudo-terminal in the parent process where the master device is located, and execute shell in the child process where the slave device is located. The information and results in the execution process are transmitted to the master device through a two-way pipeline, and the stdout is provided to the outside by the process where the master device is located.
Learn from the implementation ideas of pty.js here:
Pid_t pid = pty_forkpty (& master, name, NULL, & winp); switch (pid) {case-1: return Nan::ThrowError ("forkpty (3) failed."); case 0: if (strlen (cwd)) chdir (cwd); if (uid! =-1 & & gid! =-1) {if (setgid (gid) = =-1) {perror ("setgid (2) failed."); _ exit (1) } if (setuid (uid) = =-1) {perror ("setuid (2) failed."); _ exit (1);}} pty_execvpe (argv [0], argv, env); perror ("execvp (3) failed."); _ exit (1); default: if (pty_nonblock (master) = =-1) {return Nan::ThrowError ("Could not set master fd to nonblocking.");} Local obj = Nan::New () Nan::Set (obj, Nan::New ("fd"). ToLocalChecked (), Nan::New (master); Nan::Set (obj, Nan::New ("pid"). ToLocalChecked (), Nan::New (pid); Nan::Set (obj, Nan::New ("pty"). ToLocalChecked (), Nan::New (name). ToLocalChecked (); pty_baton * baton = new pty_baton (); baton- > exit_code = 0 Baton- > signal_code = 0; baton- > cb.Reset (Local::Cast (info [8])); baton- > pid = pid; baton- > async.data = baton; uv_async_init (uv_default_loop (), & baton- > async, pty_after_waitpid); uv_thread_create (& baton- > tid, pty_waitpid, static_cast (baton)); return info.GetReturnValue (). Set (obj);}
First, create a master-slave device through pty_forkpty (forkpty's posix implementation, which is compatible with sunOS and unix systems). Then, after setting permissions in the child process (setuid, setgid), execute the system call pty_execvpe (execvpe encapsulation). After that, the input information of the master device will be executed here (the file executed by the child process is sh, which will listen for stdin)
The parent process exposes related objects to the node layer, such as the fd of the main device (through which net.Socket objects can be created for two-way data transmission), registers the libuv message queue & baton- > async, triggers the & baton- > async message when the child process exits, and executes the pty_after_waitpid function.
Finally, the parent process creates a child process by calling uv_thread_create, which is used to listen for the exit message of the last child process (by executing the system call wait4, blocking the process listening for a specific pid, and the exit information is stored in the third parameter). The pty_waitpid function encapsulates the wait4 function and executes the uv_async_send (& baton- > async) trigger message at the end of the function.
After implementing the pty model at the bottom, you need to do some stdio operations in the node layer. Because the pseudo-terminal master device performs the creation of the system call in the parent process, and the file descriptor of the master device is exposed to the node layer through fd, then the input and output of the pseudo-terminal is completed by reading and writing the corresponding file types such as PIPE and FILE created according to fd. In fact, at the OS level, the pseudo-terminal master device is regarded as a PIPE, two-way communication. In the node layer, a socket is created to realize the bi-directional IO of the data flow through net.Socket (fd). The slave device of the pseudo terminal also has the same input as the master device, so that the corresponding command is executed in the child process, and the output of the child process is also reflected in the master device through PIPE, thus triggering the data event of the Socket object in the node layer.
The input and output descriptions of parent process, master device, child process and slave device are somewhat confusing here, which are explained here. The relationship between the parent process and the master device is that the parent process creates the master device (which can be thought of as a PIPE) through the system call, and gets the fd of the master device. The parent process implements input and output to the child process (slave device) by creating the connect socket of the fd. After the child process is created through forkpty, the login_tty operation is performed, and the stdin, stderr, and stderr of the child process are reset, all of which are copied to the fd of the slave device (the other end of the PIPE). Therefore, the input and output of the child process are associated with the fd of the slave device, and the output data of the child process takes the PIPE and reads the commands of the parent process from the PIPE. For more information, please see the forkpty implementation in the references.
In addition, the pty library provides the size setting of the pseudo terminal, so we can adjust the layout information of the output information of the pseudo terminal through parameters, so it also provides the function of adjusting the width and height of the command line on the web side. You only need to set the pseudo terminal window size in the Ptylayer, which is based on characters.
Web terminal security guarantee
There is no security guarantee to realize pseudo terminal background based on pty library provided by glibc. We want to operate a directory of the server directly through the web terminal, but the root permission can be obtained directly through the pseudo terminal background, which is intolerable for the service, because it directly affects the security of the server. All need to achieve one: multiple users can be online at the same time, can configure each user access rights, can access a specific directory, optional configuration bash commands, users are isolated from each other, users are not aware of the current environment and the environment is simple and easy to deploy.
The most suitable technology selection is docker, as a kernel-level isolation, it can make full use of hardware resources, and it is very convenient to map the relevant files of the host. However, docker is not everything. If the program runs in a docker container, assigning another container to each user becomes much more complicated and is not controlled by the operation and maintenance staff. This is the so-called DooD (docker out of docker)-- through binary files such as volume "/ usr/local/bin/docker", using the host's docker command to enable the sibling image to run the build service. However, there are many disadvantages in adopting the docker-in-docker model that is often discussed in the industry, especially at the file system level, which can be found in the references. Therefore, docker technology is not suitable for services that are already running in the container to solve user access security problems.
Next, you need to consider the solution on the stand-alone. At present, the author can only think of two options:
Command ACL, implement restricted bash chroot by command whitelist, create a system user for each user, and imprison the user access scope
First of all, the way of command whitelist should be excluded, first of all, there is no guarantee that the bash of different release linux is the same; secondly, it can not effectively exhaust all commands; finally, because of the tab command completion function provided by the pseudo terminal and the existence of special characters such as delete, it can not effectively match the current input command. Therefore, there are too many loopholes in the whitelist, so give up.
Restricted bash, triggered by / bin/bash-r, can restrict users from explicitly "cd directory", but there are many disadvantages:
Not enough to allow the execution of completely untrusted software. When a command that is found to be a shell script is executed, rbash turns off any restrictions generated in shell to execute the script. When users run bash or dash from rbash, they get unlimited shell. There are many ways to break the restricted bash shell, which is not easy to predict.
In the end, there seems to be only one solution, chroot. Chroot modifies the user's root directory to run instructions under the established root directory. Cannot jump out of this directory under the specified root directory, so you cannot access all directories of the original system; at the same time, chroot will create a system directory structure isolated from the original system, so the commands of the original system cannot be used in the "new system" because it is new and empty; finally, multiple users are isolated and transparent to fully meet our needs.
Therefore, we finally choose chroot as the security solution of the web terminal. However, using chroot requires a lot of extra processing, including not only the creation of new users, but also the initialization of commands. As mentioned above, the "new system" is empty and there are no executable binaries, such as "ls,pmd", so initializing the "new system" is necessary. But many binaries not only statically link to many libraries, but also rely on dynamic link libraries (dll) at run time, so you need to find many dll that each command depends on, which is extremely tedious. In order to help users extricate themselves from this boring process, jailkit came into being.
Jailkit, it's easy to use.
Jailkit, as its name implies, is used to imprison users. Jailkit internally uses the chroot implementation to create a user root directory and provides a series of instructions to initialize and copy binaries and all their dll, all of which can be operated through configuration files. Therefore, in the actual development, jailkit is used with initialization shell script to achieve file system isolation.
The initialization shell here refers to the preprocessing script. Because chroot needs to set the root directory for each user, create a corresponding user in shell for each user with command line permissions, and copy the basic binaries and their dll through the jailkit configuration file, such as basic shell directives, git, vim, ruby, etc., and finally do additional processing for some commands, as well as permission resets.
Some skills are still needed in the process of dealing with the file mapping between the "new system" and the original system. The author once established the mapping of other directories outside the user root directory set by chroot in the form of soft link, but when accessing the soft link in jail prison, he still reported an error and could not find the file, which was caused by the characteristics of chroot and did not have permission to access the file system outside the root directory. If the mapping is established through hard links, it is possible to modify the hard link files in the user root directory set by chroot, but operations such as deletion and creation cannot be correctly mapped to the directory of the original system, and hard links cannot connect to directories, so hard links do not meet the requirements. Finally, it is realized through mount-- bind, such as mount-- bind / home/ttt/abc / usr/local/abc. It shields the directory information (block) of the mounted directory (/ usr/local/abc) and maintains the mapping relationship between the mounted directory and the mounted directory in memory. The access to / usr/local/abc will query the block of / home/ttt/abc by passing the mapping table of memory, and then operate to realize the mapping of the directory.
Finally, after initializing the "new system", you need to execute jail-related commands through the pseudo terminal:
Sudo jk_chrootlaunch-j / usr/local/jailuser/$ {creater}-u ${creater}-x / bin/bashr
After opening the bash program, you can communicate with the web terminal input received by the main device (through websocket) through PIPE.
This is the end of the introduction on "how node.js supports multi-user web terminals". Thank you for reading. If you want to know more about the industry, you can follow the industry information channel. The editor will update different knowledge points for you every day.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.